@fudrouter/fsrouter 0.6.58 → 0.6.60

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.
Files changed (599) hide show
  1. package/bin/copyJs.js +9 -0
  2. package/bin/rewriteSseImports.js +15 -5
  3. package/dist/open-sse/executors/blackbox-web.js +1 -1
  4. package/dist/open-sse/executors/claude-web.js +1 -1
  5. package/dist/open-sse/executors/gitlab.js +1 -1
  6. package/dist/open-sse/executors/huggingchat.js +1 -1
  7. package/dist/open-sse/executors/kimi-web.js +1 -1
  8. package/dist/open-sse/executors/ninerouter.js +2 -2
  9. package/dist/open-sse/executors/qoder.js +3 -3
  10. package/dist/open-sse/executors/qwen-web.js +1 -1
  11. package/dist/open-sse/executors/yuanbao-web.js +1 -1
  12. package/dist/open-sse/handlers/chatCore/nonStreamingHandler.js +1 -1
  13. package/dist/open-sse/handlers/chatCore/requestDetail.js +1 -1
  14. package/dist/open-sse/handlers/chatCore/sseToJsonHandler.js +1 -1
  15. package/dist/open-sse/handlers/chatCore/streamingHandler.js +1 -1
  16. package/dist/open-sse/handlers/chatCore.js +1 -1
  17. package/dist/open-sse/handlers/imageProviders/leonardo.js +1 -1
  18. package/dist/open-sse/handlers/imageProviders/weavy.js +1 -1
  19. package/dist/open-sse/handlers/videoProviders/weavy.js +1 -1
  20. package/dist/open-sse/mcp-server/tools/advancedTools.js +2 -2
  21. package/dist/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  22. package/dist/open-sse/mcp-server/tools/compressionTools.js +4 -4
  23. package/dist/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  24. package/dist/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  25. package/dist/open-sse/mcp-server/tools/memoryTools.js +3 -3
  26. package/dist/open-sse/mcp-server/tools/notionTools.js +2 -2
  27. package/dist/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  28. package/dist/open-sse/mcp-server/tools/pickFastestModel.js +1 -1
  29. package/dist/open-sse/mcp-server/tools/pluginTools.js +4 -4
  30. package/dist/open-sse/mcp-server/tools/skillTools.js +2 -2
  31. package/dist/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  32. package/dist/open-sse/services/combo/quotaShareStrategy.js +1 -1
  33. package/dist/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  34. package/dist/open-sse/services/combo/sessionStickiness.js +1 -1
  35. package/dist/open-sse/services/combo/targetSorters.js +2 -2
  36. package/dist/open-sse/services/combo/validateQuality.js +1 -1
  37. package/dist/open-sse/services/thinkingBudget.js +1 -1
  38. package/dist/open-sse/services/tokenRefresh/providers.js +3 -3
  39. package/dist/open-sse/utils/providerRequestLogging.js +1 -1
  40. package/dist/open-sse/utils/responsesStatePolicy.js +1 -1
  41. package/dist/open-sse/utils/stream.js +1 -1
  42. package/dist/open-sse/utils/streamFailureFinalization.js +1 -1
  43. package/dist/open-sse/utils/usageTracking.js +1 -1
  44. package/package.json +1 -1
  45. package/open-sse/AGENTS.md +0 -39
  46. package/open-sse/config/anthropicHeaders.js +0 -87
  47. package/open-sse/config/appConstants.js +0 -238
  48. package/open-sse/config/audioRegistry.js +0 -506
  49. package/open-sse/config/cliFingerprints.js +0 -304
  50. package/open-sse/config/codexInstructions.js +0 -119
  51. package/open-sse/config/codexQuotaScopes.js +0 -42
  52. package/open-sse/config/constants.js +0 -4
  53. package/open-sse/config/contextEditing.js +0 -68
  54. package/open-sse/config/credentialLoader.js +0 -83
  55. package/open-sse/config/defaultThinkingSignature.js +0 -12
  56. package/open-sse/config/embeddingRegistry.js +0 -264
  57. package/open-sse/config/errorConfig.js +0 -96
  58. package/open-sse/config/freeModelCatalog.data.js +0 -121
  59. package/open-sse/config/freeModelCatalog.js +0 -90
  60. package/open-sse/config/freeTierCatalog.js +0 -81
  61. package/open-sse/config/googleTtsLanguages.js +0 -62
  62. package/open-sse/config/imageParamDefs.js +0 -360
  63. package/open-sse/config/imageRegistry.js +0 -493
  64. package/open-sse/config/kiroConstants.js +0 -268
  65. package/open-sse/config/mediaConfig.js +0 -27
  66. package/open-sse/config/mediaServiceKinds.js +0 -71
  67. package/open-sse/config/models.js +0 -13
  68. package/open-sse/config/moderationRegistry.js +0 -71
  69. package/open-sse/config/musicRegistry.js +0 -99
  70. package/open-sse/config/ocrRegistry.js +0 -61
  71. package/open-sse/config/ollamaModels.js +0 -19
  72. package/open-sse/config/providerErrorRules.js +0 -114
  73. package/open-sse/config/providerFieldStrips.js +0 -35
  74. package/open-sse/config/providerHeaderProfiles.js +0 -191
  75. package/open-sse/config/providerModels.js +0 -106
  76. package/open-sse/config/providerRegistry.js +0 -16
  77. package/open-sse/config/providers.js +0 -19
  78. package/open-sse/config/registryUtils.js +0 -106
  79. package/open-sse/config/rerankRegistry.js +0 -177
  80. package/open-sse/config/runtimeConfig.js +0 -96
  81. package/open-sse/config/runway.js +0 -39
  82. package/open-sse/config/searchRegistry.js +0 -153
  83. package/open-sse/config/toolCloaking.js +0 -199
  84. package/open-sse/config/ttsModels.js +0 -129
  85. package/open-sse/config/videoRegistry.js +0 -207
  86. package/open-sse/executors/adapta-web.js +0 -435
  87. package/open-sse/executors/antigravity.js +0 -534
  88. package/open-sse/executors/antigravityUpstreamError.js +0 -13
  89. package/open-sse/executors/auggie.js +0 -437
  90. package/open-sse/executors/azure-openai.js +0 -32
  91. package/open-sse/executors/azure.js +0 -57
  92. package/open-sse/executors/base.js +0 -181
  93. package/open-sse/executors/bedrock.js +0 -633
  94. package/open-sse/executors/blackbox-web.js +0 -578
  95. package/open-sse/executors/chatgpt-web.js +0 -2042
  96. package/open-sse/executors/chipotle.js +0 -357
  97. package/open-sse/executors/claude-web-with-auto-refresh.js +0 -73
  98. package/open-sse/executors/claude-web.js +0 -586
  99. package/open-sse/executors/cliproxyapi.js +0 -296
  100. package/open-sse/executors/cloudflare-ai.js +0 -46
  101. package/open-sse/executors/codebuddy-cn.js +0 -40
  102. package/open-sse/executors/codex.js +0 -1324
  103. package/open-sse/executors/commandCode.js +0 -558
  104. package/open-sse/executors/commandcode.js +0 -88
  105. package/open-sse/executors/copilot-m365-connection.js +0 -176
  106. package/open-sse/executors/copilot-m365-frames.js +0 -192
  107. package/open-sse/executors/copilot-m365-web.js +0 -299
  108. package/open-sse/executors/copilot-web.js +0 -580
  109. package/open-sse/executors/cursor.js +0 -795
  110. package/open-sse/executors/deepseek-web-with-auto-refresh.js +0 -150
  111. package/open-sse/executors/deepseek-web.js +0 -875
  112. package/open-sse/executors/default.js +0 -430
  113. package/open-sse/executors/devin-cli.js +0 -351
  114. package/open-sse/executors/doubao-web.js +0 -550
  115. package/open-sse/executors/duckduckgo-web.js +0 -629
  116. package/open-sse/executors/forceResponsesUpstream.js +0 -33
  117. package/open-sse/executors/gemini-business.js +0 -320
  118. package/open-sse/executors/gemini-cli.js +0 -89
  119. package/open-sse/executors/gemini-web.js +0 -297
  120. package/open-sse/executors/github.js +0 -379
  121. package/open-sse/executors/gitlab.js +0 -569
  122. package/open-sse/executors/glm.js +0 -361
  123. package/open-sse/executors/grok-cli.js +0 -119
  124. package/open-sse/executors/grok-web.js +0 -345
  125. package/open-sse/executors/huggingchat.js +0 -467
  126. package/open-sse/executors/iflow.js +0 -108
  127. package/open-sse/executors/index.js +0 -78
  128. package/open-sse/executors/inner-ai.js +0 -527
  129. package/open-sse/executors/kimchi.js +0 -123
  130. package/open-sse/executors/kimi-web.js +0 -325
  131. package/open-sse/executors/kimi.js +0 -97
  132. package/open-sse/executors/kiro.js +0 -503
  133. package/open-sse/executors/kiroThinking.js +0 -44
  134. package/open-sse/executors/lmarena.js +0 -395
  135. package/open-sse/executors/mimo-free.js +0 -167
  136. package/open-sse/executors/mimocode.js +0 -392
  137. package/open-sse/executors/ninerouter.js +0 -155
  138. package/open-sse/executors/nlpcloud.js +0 -438
  139. package/open-sse/executors/ollama-local.js +0 -14
  140. package/open-sse/executors/opencode-go.js +0 -41
  141. package/open-sse/executors/opencode.js +0 -32
  142. package/open-sse/executors/perplexity-web.js +0 -581
  143. package/open-sse/executors/poe-web.js +0 -133
  144. package/open-sse/executors/pollinations.js +0 -95
  145. package/open-sse/executors/puter.js +0 -31
  146. package/open-sse/executors/qoder.js +0 -448
  147. package/open-sse/executors/qwen-web.js +0 -372
  148. package/open-sse/executors/qwen.js +0 -129
  149. package/open-sse/executors/t3-chat-web.js +0 -417
  150. package/open-sse/executors/theoldllm.js +0 -290
  151. package/open-sse/executors/trae.js +0 -418
  152. package/open-sse/executors/v0-vercel-web.js +0 -141
  153. package/open-sse/executors/venice-web.js +0 -142
  154. package/open-sse/executors/vertex.js +0 -131
  155. package/open-sse/executors/vertexMedia.js +0 -236
  156. package/open-sse/executors/windsurf.js +0 -560
  157. package/open-sse/executors/xai.js +0 -46
  158. package/open-sse/executors/xiaomi-tokenplan.js +0 -19
  159. package/open-sse/executors/yuanbao-web.js +0 -385
  160. package/open-sse/executors/zed-hosted.js +0 -281
  161. package/open-sse/executors/zenmux-free.js +0 -247
  162. package/open-sse/handlers/audioSpeech.js +0 -759
  163. package/open-sse/handlers/audioTranscription.js +0 -395
  164. package/open-sse/handlers/audioTranslation.js +0 -181
  165. package/open-sse/handlers/chatCore/nonStreamingHandler.js +0 -300
  166. package/open-sse/handlers/chatCore/requestDetail.js +0 -102
  167. package/open-sse/handlers/chatCore/sseToJsonHandler.js +0 -231
  168. package/open-sse/handlers/chatCore/streamingHandler.js +0 -95
  169. package/open-sse/handlers/chatCore.js +0 -404
  170. package/open-sse/handlers/embeddingProviders/_base.js +0 -4
  171. package/open-sse/handlers/embeddingProviders/gemini.js +0 -54
  172. package/open-sse/handlers/embeddingProviders/index.js +0 -23
  173. package/open-sse/handlers/embeddingProviders/openai.js +0 -39
  174. package/open-sse/handlers/embeddingProviders/openaiCompatNode.js +0 -13
  175. package/open-sse/handlers/embeddingsCore.js +0 -126
  176. package/open-sse/handlers/fetch/index.js +0 -237
  177. package/open-sse/handlers/imageGenerationCore.js +0 -230
  178. package/open-sse/handlers/imageProviders/_base.js +0 -31
  179. package/open-sse/handlers/imageProviders/antigravity.js +0 -73
  180. package/open-sse/handlers/imageProviders/blackForestLabs.js +0 -63
  181. package/open-sse/handlers/imageProviders/cloudflareAi.js +0 -207
  182. package/open-sse/handlers/imageProviders/codex.js +0 -217
  183. package/open-sse/handlers/imageProviders/comfyui.js +0 -25
  184. package/open-sse/handlers/imageProviders/falAi.js +0 -62
  185. package/open-sse/handlers/imageProviders/gemini.js +0 -40
  186. package/open-sse/handlers/imageProviders/huggingface.js +0 -38
  187. package/open-sse/handlers/imageProviders/index.js +0 -44
  188. package/open-sse/handlers/imageProviders/leonardo.js +0 -435
  189. package/open-sse/handlers/imageProviders/nanobanana.js +0 -79
  190. package/open-sse/handlers/imageProviders/openai.js +0 -61
  191. package/open-sse/handlers/imageProviders/runwayml.js +0 -72
  192. package/open-sse/handlers/imageProviders/sdwebui.js +0 -36
  193. package/open-sse/handlers/imageProviders/stabilityAi.js +0 -59
  194. package/open-sse/handlers/imageProviders/weavy.js +0 -222
  195. package/open-sse/handlers/moderations.js +0 -92
  196. package/open-sse/handlers/ocr.js +0 -89
  197. package/open-sse/handlers/rerank.js +0 -223
  198. package/open-sse/handlers/responseSanitizer/reasoning.js +0 -144
  199. package/open-sse/handlers/responsesHandler.js +0 -99
  200. package/open-sse/handlers/search/callers.js +0 -371
  201. package/open-sse/handlers/search/chatSearch.js +0 -409
  202. package/open-sse/handlers/search/index.js +0 -201
  203. package/open-sse/handlers/search/normalizers.js +0 -223
  204. package/open-sse/handlers/search.js +0 -1056
  205. package/open-sse/handlers/sseParser.js +0 -469
  206. package/open-sse/handlers/sttCore.js +0 -193
  207. package/open-sse/handlers/ttsCore.js +0 -74
  208. package/open-sse/handlers/ttsProviders/_base.js +0 -39
  209. package/open-sse/handlers/ttsProviders/edgeTts.js +0 -89
  210. package/open-sse/handlers/ttsProviders/elevenlabs.js +0 -48
  211. package/open-sse/handlers/ttsProviders/gemini.js +0 -117
  212. package/open-sse/handlers/ttsProviders/genericFormats.js +0 -169
  213. package/open-sse/handlers/ttsProviders/googleTts.js +0 -54
  214. package/open-sse/handlers/ttsProviders/index.js +0 -50
  215. package/open-sse/handlers/ttsProviders/localDevice.js +0 -87
  216. package/open-sse/handlers/ttsProviders/minimax.js +0 -59
  217. package/open-sse/handlers/ttsProviders/openai.js +0 -30
  218. package/open-sse/handlers/ttsProviders/openrouter.js +0 -70
  219. package/open-sse/handlers/usageExtractor.js +0 -93
  220. package/open-sse/handlers/videoGenerationCore.js +0 -119
  221. package/open-sse/handlers/videoProviders/index.js +0 -22
  222. package/open-sse/handlers/videoProviders/leonardo.js +0 -511
  223. package/open-sse/handlers/videoProviders/weavy.js +0 -198
  224. package/open-sse/handlers/webFetch.js +0 -200
  225. package/open-sse/index.js +0 -79
  226. package/open-sse/mcp-server/audit.js +0 -283
  227. package/open-sse/mcp-server/catalog.js +0 -184
  228. package/open-sse/mcp-server/descriptionCompressor.js +0 -175
  229. package/open-sse/mcp-server/httpAuthContext.js +0 -32
  230. package/open-sse/mcp-server/httpTransport.js +0 -229
  231. package/open-sse/mcp-server/index.js +0 -33
  232. package/open-sse/mcp-server/mcpCallerIdentity.js +0 -21
  233. package/open-sse/mcp-server/runtimeHeartbeat.js +0 -110
  234. package/open-sse/mcp-server/schemas/a2a.js +0 -153
  235. package/open-sse/mcp-server/schemas/audit.js +0 -17
  236. package/open-sse/mcp-server/schemas/index.js +0 -166
  237. package/open-sse/mcp-server/schemas/pickFastestModel.js +0 -90
  238. package/open-sse/mcp-server/schemas/toolDefinition.js +0 -0
  239. package/open-sse/mcp-server/schemas/toolSearch.js +0 -32
  240. package/open-sse/mcp-server/schemas/tools.js +0 -1219
  241. package/open-sse/mcp-server/scopeEnforcement.js +0 -80
  242. package/open-sse/mcp-server/server.js +0 -1168
  243. package/open-sse/mcp-server/toolCardinality.js +0 -78
  244. package/open-sse/mcp-server/toolSearch/catalog.js +0 -66
  245. package/open-sse/mcp-server/toolSearch/handler.js +0 -20
  246. package/open-sse/mcp-server/toolSearch/index.js +0 -10
  247. package/open-sse/mcp-server/toolSearch/register.js +0 -21
  248. package/open-sse/mcp-server/toolSearch/search.js +0 -55
  249. package/open-sse/mcp-server/toolSearch/signature.js +0 -67
  250. package/open-sse/mcp-server/tools/advancedTools.js +0 -893
  251. package/open-sse/mcp-server/tools/agentSkillTools.js +0 -69
  252. package/open-sse/mcp-server/tools/compressionTools.js +0 -309
  253. package/open-sse/mcp-server/tools/gamificationTools.js +0 -134
  254. package/open-sse/mcp-server/tools/githubSkillTools.js +0 -102
  255. package/open-sse/mcp-server/tools/memoryTools.js +0 -118
  256. package/open-sse/mcp-server/tools/notionTools.js +0 -101
  257. package/open-sse/mcp-server/tools/obsidianTools.js +0 -307
  258. package/open-sse/mcp-server/tools/pickFastestModel.js +0 -223
  259. package/open-sse/mcp-server/tools/pluginTools.js +0 -181
  260. package/open-sse/mcp-server/tools/poolTools.js +0 -139
  261. package/open-sse/mcp-server/tools/skillTools.js +0 -113
  262. package/open-sse/package.json +0 -10
  263. package/open-sse/providers/REGISTRY_TEMPLATE.js +0 -98
  264. package/open-sse/providers/capabilities.js +0 -293
  265. package/open-sse/providers/index.js +0 -51
  266. package/open-sse/providers/models/helpers.js +0 -20
  267. package/open-sse/providers/models/namePatterns.js +0 -33
  268. package/open-sse/providers/models/schema.js +0 -40
  269. package/open-sse/providers/pricing.js +0 -308
  270. package/open-sse/providers/registry/alicode-intl.js +0 -30
  271. package/open-sse/providers/registry/alicode.js +0 -31
  272. package/open-sse/providers/registry/anthropic.js +0 -37
  273. package/open-sse/providers/registry/antigravity.js +0 -81
  274. package/open-sse/providers/registry/assemblyai.js +0 -38
  275. package/open-sse/providers/registry/aws-polly.js +0 -45
  276. package/open-sse/providers/registry/azure.js +0 -21
  277. package/open-sse/providers/registry/black-forest-labs.js +0 -32
  278. package/open-sse/providers/registry/blackbox.js +0 -41
  279. package/open-sse/providers/registry/brave-search.js +0 -35
  280. package/open-sse/providers/registry/byteplus.js +0 -35
  281. package/open-sse/providers/registry/cartesia.js +0 -36
  282. package/open-sse/providers/registry/cerebras.js +0 -31
  283. package/open-sse/providers/registry/chutes.js +0 -24
  284. package/open-sse/providers/registry/claude.js +0 -87
  285. package/open-sse/providers/registry/cline.js +0 -51
  286. package/open-sse/providers/registry/clinepass.js +0 -57
  287. package/open-sse/providers/registry/cloudflare-ai.js +0 -55
  288. package/open-sse/providers/registry/codebuddy-cn.js +0 -77
  289. package/open-sse/providers/registry/codex.js +0 -100
  290. package/open-sse/providers/registry/cohere.js +0 -27
  291. package/open-sse/providers/registry/comfyui.js +0 -20
  292. package/open-sse/providers/registry/commandcode.js +0 -43
  293. package/open-sse/providers/registry/coqui.js +0 -30
  294. package/open-sse/providers/registry/cursor.js +0 -58
  295. package/open-sse/providers/registry/deepgram.js +0 -33
  296. package/open-sse/providers/registry/deepseek.js +0 -51
  297. package/open-sse/providers/registry/digitalocean.js +0 -92
  298. package/open-sse/providers/registry/edge-tts.js +0 -24
  299. package/open-sse/providers/registry/elevenlabs.js +0 -35
  300. package/open-sse/providers/registry/exa.js +0 -50
  301. package/open-sse/providers/registry/fal-ai.js +0 -34
  302. package/open-sse/providers/registry/featherless.js +0 -34
  303. package/open-sse/providers/registry/firecrawl.js +0 -34
  304. package/open-sse/providers/registry/fireworks.js +0 -29
  305. package/open-sse/providers/registry/gemini-cli.js +0 -58
  306. package/open-sse/providers/registry/gemini.js +0 -83
  307. package/open-sse/providers/registry/github.js +0 -88
  308. package/open-sse/providers/registry/gitlab.js +0 -32
  309. package/open-sse/providers/registry/glm-cn.js +0 -35
  310. package/open-sse/providers/registry/glm.js +0 -58
  311. package/open-sse/providers/registry/google-pse.js +0 -35
  312. package/open-sse/providers/registry/google-tts.js +0 -24
  313. package/open-sse/providers/registry/grok-cli.js +0 -86
  314. package/open-sse/providers/registry/grok-web.js +0 -39
  315. package/open-sse/providers/registry/groq.js +0 -37
  316. package/open-sse/providers/registry/huggingface.js +0 -34
  317. package/open-sse/providers/registry/hyperbolic.js +0 -35
  318. package/open-sse/providers/registry/ibm-bob.js +0 -27
  319. package/open-sse/providers/registry/iflow.js +0 -52
  320. package/open-sse/providers/registry/index.js +0 -210
  321. package/open-sse/providers/registry/inworld.js +0 -36
  322. package/open-sse/providers/registry/jina-ai.js +0 -42
  323. package/open-sse/providers/registry/jina-reader.js +0 -34
  324. package/open-sse/providers/registry/kilocode.js +0 -51
  325. package/open-sse/providers/registry/kimchi.js +0 -49
  326. package/open-sse/providers/registry/kimi-coding.js +0 -65
  327. package/open-sse/providers/registry/kimi.js +0 -56
  328. package/open-sse/providers/registry/kiro.js +0 -115
  329. package/open-sse/providers/registry/linkup.js +0 -34
  330. package/open-sse/providers/registry/local-device.js +0 -24
  331. package/open-sse/providers/registry/mimo-free.js +0 -24
  332. package/open-sse/providers/registry/minimax-cn.js +0 -76
  333. package/open-sse/providers/registry/minimax.js +0 -83
  334. package/open-sse/providers/registry/mistral.js +0 -34
  335. package/open-sse/providers/registry/mmf.js +0 -19
  336. package/open-sse/providers/registry/nanobanana.js +0 -35
  337. package/open-sse/providers/registry/nebius.js +0 -27
  338. package/open-sse/providers/registry/nvidia.js +0 -43
  339. package/open-sse/providers/registry/ollama-local.js +0 -19
  340. package/open-sse/providers/registry/ollama.js +0 -36
  341. package/open-sse/providers/registry/openai.js +0 -84
  342. package/open-sse/providers/registry/opencode-go.js +0 -41
  343. package/open-sse/providers/registry/opencode.js +0 -25
  344. package/open-sse/providers/registry/openrouter.js +0 -60
  345. package/open-sse/providers/registry/perplexity-agent.js +0 -49
  346. package/open-sse/providers/registry/perplexity-web.js +0 -33
  347. package/open-sse/providers/registry/perplexity.js +0 -37
  348. package/open-sse/providers/registry/playht.js +0 -36
  349. package/open-sse/providers/registry/qoder.js +0 -54
  350. package/open-sse/providers/registry/qwen.js +0 -33
  351. package/open-sse/providers/registry/recraft.js +0 -24
  352. package/open-sse/providers/registry/runwayml.js +0 -30
  353. package/open-sse/providers/registry/sdwebui.js +0 -20
  354. package/open-sse/providers/registry/searchapi.js +0 -35
  355. package/open-sse/providers/registry/searxng.js +0 -35
  356. package/open-sse/providers/registry/serper.js +0 -35
  357. package/open-sse/providers/registry/siliconflow.js +0 -39
  358. package/open-sse/providers/registry/stability-ai.js +0 -31
  359. package/open-sse/providers/registry/tavily.js +0 -50
  360. package/open-sse/providers/registry/together.js +0 -31
  361. package/open-sse/providers/registry/topaz.js +0 -19
  362. package/open-sse/providers/registry/tortoise.js +0 -30
  363. package/open-sse/providers/registry/venice.js +0 -56
  364. package/open-sse/providers/registry/vercel-ai-gateway.js +0 -41
  365. package/open-sse/providers/registry/vertex-partner.js +0 -29
  366. package/open-sse/providers/registry/vertex.js +0 -32
  367. package/open-sse/providers/registry/volcengine-ark.js +0 -35
  368. package/open-sse/providers/registry/voyage-ai.js +0 -30
  369. package/open-sse/providers/registry/xai.js +0 -45
  370. package/open-sse/providers/registry/xiaomi-mimo.js +0 -46
  371. package/open-sse/providers/registry/xiaomi-tokenplan.js +0 -63
  372. package/open-sse/providers/registry/youcom.js +0 -35
  373. package/open-sse/providers/schema.js +0 -76
  374. package/open-sse/providers/shared.js +0 -74
  375. package/open-sse/providers/thinkingLevels.js +0 -48
  376. package/open-sse/rtk/applyFilter.js +0 -15
  377. package/open-sse/rtk/autodetect.js +0 -111
  378. package/open-sse/rtk/caveman.js +0 -100
  379. package/open-sse/rtk/cavemanPrompts.js +0 -78
  380. package/open-sse/rtk/constants.js +0 -55
  381. package/open-sse/rtk/filters/buildOutput.js +0 -127
  382. package/open-sse/rtk/filters/dedupLog.js +0 -44
  383. package/open-sse/rtk/filters/find.js +0 -50
  384. package/open-sse/rtk/filters/gitDiff.js +0 -92
  385. package/open-sse/rtk/filters/gitLog.js +0 -99
  386. package/open-sse/rtk/filters/gitStatus.js +0 -117
  387. package/open-sse/rtk/filters/grep.js +0 -48
  388. package/open-sse/rtk/filters/ls.js +0 -79
  389. package/open-sse/rtk/filters/readNumbered.js +0 -27
  390. package/open-sse/rtk/filters/searchList.js +0 -52
  391. package/open-sse/rtk/filters/smartTruncate.js +0 -15
  392. package/open-sse/rtk/filters/tree.js +0 -32
  393. package/open-sse/rtk/headroom.js +0 -215
  394. package/open-sse/rtk/index.js +0 -155
  395. package/open-sse/rtk/paleo.js +0 -47
  396. package/open-sse/rtk/ponytail.js +0 -9
  397. package/open-sse/rtk/ponytailPrompt.js +0 -52
  398. package/open-sse/rtk/ponytailPrompts.js +0 -76
  399. package/open-sse/rtk/pxpipe.js +0 -104
  400. package/open-sse/rtk/registry.js +0 -38
  401. package/open-sse/rtk/systemInject.js +0 -98
  402. package/open-sse/services/accountFallback.js +0 -323
  403. package/open-sse/services/antigravityHeaders.js +0 -91
  404. package/open-sse/services/antigravityVersion.js +0 -154
  405. package/open-sse/services/clinepassModels.js +0 -63
  406. package/open-sse/services/codexQuotaFetcher.js +0 -312
  407. package/open-sse/services/codexVerbosity.js +0 -30
  408. package/open-sse/services/combo/context.js +0 -12
  409. package/open-sse/services/combo/fingerprintExpansion.js +0 -51
  410. package/open-sse/services/combo/headroomRanking.js +0 -28
  411. package/open-sse/services/combo/quotaExhaustionCutoff.js +0 -87
  412. package/open-sse/services/combo/quotaScoring.js +0 -226
  413. package/open-sse/services/combo/quotaShareConcurrency.js +0 -25
  414. package/open-sse/services/combo/quotaShareInflight.js +0 -50
  415. package/open-sse/services/combo/quotaShareStrategy.js +0 -130
  416. package/open-sse/services/combo/resolveAutoStrategy.js +0 -231
  417. package/open-sse/services/combo/responseValidation.js +0 -140
  418. package/open-sse/services/combo/runtimeUnits.js +0 -195
  419. package/open-sse/services/combo/sessionStickiness.js +0 -128
  420. package/open-sse/services/combo/shadowRouting.js +0 -131
  421. package/open-sse/services/combo/targetExhaustion.js +0 -75
  422. package/open-sse/services/combo/targetSorters.js +0 -126
  423. package/open-sse/services/combo/targetTimeoutRunner.js +0 -65
  424. package/open-sse/services/combo/validateQuality.js +0 -271
  425. package/open-sse/services/combo.js +0 -571
  426. package/open-sse/services/comboAgentMiddleware.js +0 -91
  427. package/open-sse/services/comboConfig.js +0 -153
  428. package/open-sse/services/comboManifestMetrics.js +0 -10
  429. package/open-sse/services/comboMetrics.js +0 -278
  430. package/open-sse/services/compact.js +0 -71
  431. package/open-sse/services/copilotModels.js +0 -155
  432. package/open-sse/services/emergencyFallback.js +0 -109
  433. package/open-sse/services/errorClassifier.js +0 -190
  434. package/open-sse/services/evalRouting.js +0 -201
  435. package/open-sse/services/freeWebSearch.js +0 -4
  436. package/open-sse/services/fusion.js +0 -223
  437. package/open-sse/services/intentClassifier.js +0 -631
  438. package/open-sse/services/kimchiModels.js +0 -176
  439. package/open-sse/services/kiroModels.js +0 -332
  440. package/open-sse/services/model.js +0 -136
  441. package/open-sse/services/modelCapabilities.js +0 -5
  442. package/open-sse/services/modelDeprecation.js +0 -101
  443. package/open-sse/services/modelFamilyFallback.js +0 -166
  444. package/open-sse/services/oauthCredentialManager.js +0 -156
  445. package/open-sse/services/pipeline.js +0 -107
  446. package/open-sse/services/projectId.js +0 -306
  447. package/open-sse/services/provider.js +0 -169
  448. package/open-sse/services/providerCooldownTracker.js +0 -94
  449. package/open-sse/services/providerDefaultRateLimit.js +0 -11
  450. package/open-sse/services/proxyAutoSelector.js +0 -24
  451. package/open-sse/services/qoderModels.js +0 -214
  452. package/open-sse/services/quotaFetchThrottle.js +0 -103
  453. package/open-sse/services/quotaMonitor.js +0 -310
  454. package/open-sse/services/quotaPreflight.js +0 -266
  455. package/open-sse/services/rateLimitManager/headers.js +0 -56
  456. package/open-sse/services/rateLimitManager.js +0 -616
  457. package/open-sse/services/rateLimitSemaphore.js +0 -112
  458. package/open-sse/services/responsesInputSanitizer.js +0 -99
  459. package/open-sse/services/slidingWindowLimiter.js +0 -44
  460. package/open-sse/services/streamRecovery.js +0 -355
  461. package/open-sse/services/taskAwareRouter.js +0 -227
  462. package/open-sse/services/taskAwareRouting.js +0 -332
  463. package/open-sse/services/thinkingBudget.js +0 -247
  464. package/open-sse/services/tokenRefresh/dedup.js +0 -31
  465. package/open-sse/services/tokenRefresh/providers.js +0 -624
  466. package/open-sse/services/tokenRefresh.js +0 -254
  467. package/open-sse/services/usage/claude.js +0 -147
  468. package/open-sse/services/usage/codebuddy-cn.js +0 -138
  469. package/open-sse/services/usage/codex.js +0 -267
  470. package/open-sse/services/usage/github.js +0 -100
  471. package/open-sse/services/usage/google.js +0 -241
  472. package/open-sse/services/usage/grok-cli.js +0 -274
  473. package/open-sse/services/usage/kiro.js +0 -188
  474. package/open-sse/services/usage/minimax.js +0 -234
  475. package/open-sse/services/usage/misc.js +0 -288
  476. package/open-sse/services/usage/shared.js +0 -70
  477. package/open-sse/services/usage.js +0 -62
  478. package/open-sse/services/usageDb.js +0 -2
  479. package/open-sse/services/webSearchRouting.js +0 -25
  480. package/open-sse/services/wildcardRouter.js +0 -59
  481. package/open-sse/shared/clineAuth.js +0 -37
  482. package/open-sse/shared/machineId.js +0 -19
  483. package/open-sse/shared/qoder/constants.js +0 -64
  484. package/open-sse/shared/qoder/cosy.js +0 -175
  485. package/open-sse/shared/qoder/encoding.js +0 -55
  486. package/open-sse/transformer/responsesTransformer.js +0 -439
  487. package/open-sse/transformer/streamToJsonConverter.js +0 -103
  488. package/open-sse/translator/concerns/chunk.js +0 -11
  489. package/open-sse/translator/concerns/finishReason.js +0 -63
  490. package/open-sse/translator/concerns/image.js +0 -124
  491. package/open-sse/translator/concerns/json.js +0 -5
  492. package/open-sse/translator/concerns/message.js +0 -7
  493. package/open-sse/translator/concerns/modality.js +0 -155
  494. package/open-sse/translator/concerns/paramSupport.js +0 -75
  495. package/open-sse/translator/concerns/prefetch.js +0 -96
  496. package/open-sse/translator/concerns/reasoning.js +0 -24
  497. package/open-sse/translator/concerns/thinking.js +0 -53
  498. package/open-sse/translator/concerns/thinkingUnified.js +0 -329
  499. package/open-sse/translator/concerns/toolCall.js +0 -153
  500. package/open-sse/translator/concerns/usage.js +0 -69
  501. package/open-sse/translator/formats/claude.js +0 -368
  502. package/open-sse/translator/formats/gemini.js +0 -380
  503. package/open-sse/translator/formats/maxTokens.js +0 -34
  504. package/open-sse/translator/formats/openai.js +0 -134
  505. package/open-sse/translator/formats/responsesApi.js +0 -141
  506. package/open-sse/translator/formats.js +0 -36
  507. package/open-sse/translator/helpers/claudeHelper.js +0 -216
  508. package/open-sse/translator/helpers/geminiHelper.js +0 -372
  509. package/open-sse/translator/helpers/imageHelper.js +0 -34
  510. package/open-sse/translator/helpers/maxTokensHelper.js +0 -27
  511. package/open-sse/translator/helpers/openaiHelper.js +0 -130
  512. package/open-sse/translator/helpers/responsesApiHelper.js +0 -139
  513. package/open-sse/translator/helpers/toolCallHelper.js +0 -148
  514. package/open-sse/translator/index.js +0 -252
  515. package/open-sse/translator/request/antigravity-to-openai.js +0 -242
  516. package/open-sse/translator/request/claude-to-kiro.js +0 -478
  517. package/open-sse/translator/request/claude-to-openai.js +0 -263
  518. package/open-sse/translator/request/gemini-to-openai.js +0 -152
  519. package/open-sse/translator/request/openai-responses.js +0 -385
  520. package/open-sse/translator/request/openai-to-claude.js +0 -383
  521. package/open-sse/translator/request/openai-to-commandcode.js +0 -176
  522. package/open-sse/translator/request/openai-to-cursor.js +0 -185
  523. package/open-sse/translator/request/openai-to-gemini.js +0 -442
  524. package/open-sse/translator/request/openai-to-kiro.js +0 -607
  525. package/open-sse/translator/request/openai-to-kiro.old.js +0 -278
  526. package/open-sse/translator/request/openai-to-ollama.js +0 -195
  527. package/open-sse/translator/request/openai-to-vertex.js +0 -42
  528. package/open-sse/translator/response/claude-to-openai.js +0 -195
  529. package/open-sse/translator/response/commandcode-to-openai.js +0 -188
  530. package/open-sse/translator/response/cursor-to-openai.js +0 -30
  531. package/open-sse/translator/response/gemini-to-openai.js +0 -147
  532. package/open-sse/translator/response/kiro-to-claude.js +0 -261
  533. package/open-sse/translator/response/kiro-to-openai.js +0 -160
  534. package/open-sse/translator/response/ollama-to-openai.js +0 -134
  535. package/open-sse/translator/response/openai-responses.js +0 -535
  536. package/open-sse/translator/response/openai-to-antigravity.js +0 -123
  537. package/open-sse/translator/response/openai-to-claude.js +0 -265
  538. package/open-sse/translator/schema/blocks.js +0 -43
  539. package/open-sse/translator/schema/defaults.js +0 -7
  540. package/open-sse/translator/schema/finishReasons.js +0 -27
  541. package/open-sse/translator/schema/index.js +0 -8
  542. package/open-sse/translator/schema/roles.js +0 -16
  543. package/open-sse/utils/agentGoalPolicy.js +0 -85
  544. package/open-sse/utils/aiSdkCompat.js +0 -75
  545. package/open-sse/utils/bypassHandler.js +0 -298
  546. package/open-sse/utils/cacheControlPolicy.js +0 -189
  547. package/open-sse/utils/claudeCloaking.js +0 -155
  548. package/open-sse/utils/claudeHeaderCache.js +0 -70
  549. package/open-sse/utils/claudeSignature.js +0 -41
  550. package/open-sse/utils/clientDetector.js +0 -63
  551. package/open-sse/utils/codebuddySanitizer.js +0 -96
  552. package/open-sse/utils/composerToolCalls.js +0 -158
  553. package/open-sse/utils/cors.js +0 -13
  554. package/open-sse/utils/cursorChecksum.js +0 -149
  555. package/open-sse/utils/cursorImages.js +0 -224
  556. package/open-sse/utils/cursorProtobuf.js +0 -904
  557. package/open-sse/utils/cursorVersionDetector.js +0 -55
  558. package/open-sse/utils/debugLog.js +0 -14
  559. package/open-sse/utils/diagnostics.js +0 -143
  560. package/open-sse/utils/error.js +0 -164
  561. package/open-sse/utils/estimateSize.js +0 -33
  562. package/open-sse/utils/finishReason.js +0 -32
  563. package/open-sse/utils/flattenToolHistory.js +0 -68
  564. package/open-sse/utils/headers.js +0 -36
  565. package/open-sse/utils/heapPressure.js +0 -35
  566. package/open-sse/utils/jsonToSse.js +0 -125
  567. package/open-sse/utils/keepaliveThreshold.js +0 -40
  568. package/open-sse/utils/logger.js +0 -104
  569. package/open-sse/utils/noThinkingAlias.js +0 -74
  570. package/open-sse/utils/number.js +0 -7
  571. package/open-sse/utils/ollamaTransform.js +0 -85
  572. package/open-sse/utils/opencodeHeaders.js +0 -47
  573. package/open-sse/utils/progressTracker.js +0 -81
  574. package/open-sse/utils/providerRequestLogging.js +0 -219
  575. package/open-sse/utils/proxyFetch.js +0 -369
  576. package/open-sse/utils/reasoningContentInjector.js +0 -79
  577. package/open-sse/utils/reasoningFields.js +0 -70
  578. package/open-sse/utils/requestLogger.js +0 -260
  579. package/open-sse/utils/responsesInputNormalization.js +0 -92
  580. package/open-sse/utils/responsesStatePolicy.js +0 -52
  581. package/open-sse/utils/responsesStreamHelpers.js +0 -49
  582. package/open-sse/utils/sessionManager.js +0 -240
  583. package/open-sse/utils/sleep.js +0 -6
  584. package/open-sse/utils/sse.js +0 -14
  585. package/open-sse/utils/sseConstants.js +0 -23
  586. package/open-sse/utils/sseHeartbeat.js +0 -104
  587. package/open-sse/utils/stream.js +0 -517
  588. package/open-sse/utils/streamFailureFinalization.js +0 -134
  589. package/open-sse/utils/streamHandler.js +0 -250
  590. package/open-sse/utils/streamHelpers.js +0 -137
  591. package/open-sse/utils/textualToolCall.js +0 -104
  592. package/open-sse/utils/thinkCloseMarker.js +0 -72
  593. package/open-sse/utils/thinkTagParser.js +0 -146
  594. package/open-sse/utils/toolCallArguments.js +0 -12
  595. package/open-sse/utils/toolDeduper.js +0 -49
  596. package/open-sse/utils/toolSources.js +0 -31
  597. package/open-sse/utils/upstreamResponseHeaders.js +0 -25
  598. package/open-sse/utils/urlSanitize.js +0 -15
  599. package/open-sse/utils/usageTracking.js +0 -347
@@ -1,2042 +0,0 @@
1
- import { BaseExecutor } from "./base.ts";
2
- import { describeChatGptWebHttpError } from "./chatgptWebErrors.ts";
3
- import { prepareToolMessages } from "../translator/webTools.ts";
4
- import { buildToolModeResponse } from "./chatgptWebTools.ts";
5
- import { createHash, randomUUID, randomBytes } from "node:crypto";
6
- import { sha3_512Hex } from "../utils/sha3-512.ts";
7
- import {
8
- tlsFetchChatGpt,
9
- TlsClientUnavailableError
10
- } from "../services/chatgptTlsClient.ts";
11
- import {
12
- storeChatGptImage,
13
- getChatGptImageConversationContext,
14
- __resetChatGptImageCacheForTesting
15
- } from "../services/chatgptImageCache.ts";
16
- import { isThinkingCapableModel, resolveChatGptModel } from "./chatgpt-web/models.ts";
17
- const CHATGPT_BASE = "https://chatgpt.com";
18
- const SESSION_URL = `${CHATGPT_BASE}/api/auth/session`;
19
- const SENTINEL_PREPARE_URL = `${CHATGPT_BASE}/backend-api/sentinel/chat-requirements/prepare`;
20
- const SENTINEL_CR_URL = `${CHATGPT_BASE}/backend-api/sentinel/chat-requirements`;
21
- const CONV_URL = `${CHATGPT_BASE}/backend-api/f/conversation`;
22
- const USER_LAST_USED_MODEL_CONFIG_URL = `${CHATGPT_BASE}/backend-api/settings/user_last_used_model_config`;
23
- const DEFAULT_PRO_POLL_TIMEOUT_MS = 20 * 6e4;
24
- const DEFAULT_PRO_POLL_INTERVAL_MS = 4e3;
25
- const CHATGPT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) Gecko/20100101 Firefox/152.0";
26
- const OAI_CLIENT_VERSION = "prod-81e0c5cdf6140e8c5db714d613337f4aeab94029";
27
- const OAI_CLIENT_BUILD_NUMBER = "6128297";
28
- const deviceIdCache = /* @__PURE__ */ new Map();
29
- function deviceIdFor(cookie) {
30
- const key = cookieKey(cookie);
31
- let id = deviceIdCache.get(key);
32
- if (!id) {
33
- const h = createHash("sha256").update(cookie).digest("hex");
34
- id = `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-${(parseInt(h.slice(16, 17), 16) & 3 | 8).toString(16)}${h.slice(17, 20)}-` + h.slice(20, 32);
35
- if (deviceIdCache.size >= 200) {
36
- const first = deviceIdCache.keys().next().value;
37
- if (first) deviceIdCache.delete(first);
38
- }
39
- deviceIdCache.set(key, id);
40
- }
41
- return id;
42
- }
43
- function browserHeaders() {
44
- return {
45
- Accept: "*/*",
46
- "Accept-Language": "en-US,en;q=0.9",
47
- "Cache-Control": "no-cache",
48
- Origin: CHATGPT_BASE,
49
- Pragma: "no-cache",
50
- Referer: `${CHATGPT_BASE}/`,
51
- "Sec-Fetch-Dest": "empty",
52
- "Sec-Fetch-Mode": "cors",
53
- "Sec-Fetch-Site": "same-origin",
54
- "User-Agent": CHATGPT_USER_AGENT
55
- };
56
- }
57
- function oaiHeaders(sessionId, deviceId) {
58
- return {
59
- "OAI-Language": "en-US",
60
- "OAI-Device-Id": deviceId,
61
- "OAI-Client-Version": OAI_CLIENT_VERSION,
62
- "OAI-Client-Build-Number": OAI_CLIENT_BUILD_NUMBER,
63
- "OAI-Session-Id": sessionId
64
- };
65
- }
66
- const TOKEN_TTL_MS = 5 * 60 * 1e3;
67
- const tokenCache = /* @__PURE__ */ new Map();
68
- function cookieKey(cookie) {
69
- return createHash("sha256").update(cookie).digest("hex").slice(0, 16);
70
- }
71
- function tokenLookup(cookie) {
72
- const entry = tokenCache.get(cookieKey(cookie));
73
- if (!entry) return null;
74
- if (Date.now() >= entry.expiresAt) {
75
- tokenCache.delete(cookieKey(cookie));
76
- return null;
77
- }
78
- return entry;
79
- }
80
- const TOKEN_CACHE_MAX = 200;
81
- function tokenStore(cookie, entry) {
82
- if (tokenCache.size >= TOKEN_CACHE_MAX && !tokenCache.has(cookieKey(cookie))) {
83
- const firstKey = tokenCache.keys().next().value;
84
- if (firstKey) tokenCache.delete(firstKey);
85
- }
86
- tokenCache.set(cookieKey(cookie), entry);
87
- }
88
- const SESSION_TOKEN_FAMILY_RE = /^__Secure-next-auth\.session-token(?:\.\d+)?$/;
89
- function mergeRefreshedCookie(originalCookie, setCookieHeader) {
90
- if (!setCookieHeader) return null;
91
- const matches = Array.from(
92
- setCookieHeader.matchAll(/(__Secure-next-auth\.session-token(?:\.\d+)?)=([^;,\s]+)/g)
93
- );
94
- if (matches.length === 0) return null;
95
- const refreshed = /* @__PURE__ */ new Map();
96
- for (const m of matches) refreshed.set(m[1], m[2]);
97
- let blob = originalCookie.trim();
98
- if (/^cookie\s*:\s*/i.test(blob)) blob = blob.replace(/^cookie\s*:\s*/i, "");
99
- if (!/=/.test(blob)) {
100
- return Array.from(refreshed, ([k, v]) => `${k}=${v}`).join("; ");
101
- }
102
- const pairs = blob.split(/;\s*/).filter(Boolean);
103
- const result = [];
104
- let mutated = false;
105
- let droppedStale = false;
106
- for (const pair of pairs) {
107
- const eqIdx = pair.indexOf("=");
108
- if (eqIdx < 0) {
109
- result.push(pair);
110
- continue;
111
- }
112
- const name = pair.slice(0, eqIdx).trim();
113
- const value = pair.slice(eqIdx + 1);
114
- if (SESSION_TOKEN_FAMILY_RE.test(name)) {
115
- if (!refreshed.has(name) || refreshed.get(name) !== value) mutated = true;
116
- droppedStale = true;
117
- continue;
118
- }
119
- result.push(`${name}=${value}`);
120
- }
121
- for (const [name, value] of refreshed) {
122
- result.push(`${name}=${value}`);
123
- }
124
- if (!droppedStale) mutated = true;
125
- return mutated ? result.join("; ") : null;
126
- }
127
- function buildSessionCookieHeader(rawInput) {
128
- let s = rawInput.trim();
129
- if (/^cookie\s*:\s*/i.test(s)) s = s.replace(/^cookie\s*:\s*/i, "");
130
- if (/__Secure-next-auth\.session-token(?:\.\d+)?\s*=/.test(s)) {
131
- return s;
132
- }
133
- return `__Secure-next-auth.session-token=${s}`;
134
- }
135
- async function exchangeSession(cookie, signal) {
136
- const cached = tokenLookup(cookie);
137
- if (cached) return cached;
138
- const headers = {
139
- ...browserHeaders(),
140
- Accept: "application/json",
141
- Cookie: buildSessionCookieHeader(cookie)
142
- };
143
- const response = await tlsFetchChatGpt(SESSION_URL, {
144
- method: "GET",
145
- headers,
146
- timeoutMs: 3e4,
147
- signal
148
- });
149
- if (response.status === 401 || response.status === 403) {
150
- throw new SessionAuthError("Invalid session cookie");
151
- }
152
- if (response.status >= 400) {
153
- throw new Error(`Session exchange failed (HTTP ${response.status})`);
154
- }
155
- const refreshed = mergeRefreshedCookie(cookie, response.headers.get("set-cookie"));
156
- let data = {};
157
- try {
158
- data = JSON.parse(response.text || "{}");
159
- } catch {
160
- console.warn("[chatgpt-web] session response JSON parse failed");
161
- }
162
- if (!data.accessToken) {
163
- throw new SessionAuthError("Session response missing accessToken \u2014 cookie likely expired");
164
- }
165
- const expiresAt = data.expires ? new Date(data.expires).getTime() : Date.now() + TOKEN_TTL_MS;
166
- const entry = {
167
- accessToken: data.accessToken,
168
- accountId: data.user?.id ?? null,
169
- expiresAt: Math.min(expiresAt, Date.now() + TOKEN_TTL_MS),
170
- refreshedCookie: refreshed ?? void 0
171
- };
172
- tokenStore(cookie, entry);
173
- return entry;
174
- }
175
- class SessionAuthError extends Error {
176
- constructor(message) {
177
- super(message);
178
- this.name = "SessionAuthError";
179
- }
180
- }
181
- const warmupCache = /* @__PURE__ */ new Map();
182
- const WARMUP_TTL_MS = 6e4;
183
- const WARMUP_CACHE_MAX = 200;
184
- async function runSessionWarmup(accessToken, accountId, sessionId, deviceId, cookie, signal, log) {
185
- const key = cookieKey(cookie) + ":" + accessToken.slice(-8);
186
- const now = Date.now();
187
- const last = warmupCache.get(key);
188
- if (last && now - last < WARMUP_TTL_MS) return;
189
- if (warmupCache.size >= WARMUP_CACHE_MAX && !warmupCache.has(key)) {
190
- const first = warmupCache.keys().next().value;
191
- if (first) warmupCache.delete(first);
192
- }
193
- warmupCache.set(key, now);
194
- const headers = {
195
- ...browserHeaders(),
196
- ...oaiHeaders(sessionId, deviceId),
197
- Accept: "*/*",
198
- Authorization: `Bearer ${accessToken}`,
199
- Cookie: buildSessionCookieHeader(cookie),
200
- Priority: "u=1, i"
201
- };
202
- if (accountId) headers["chatgpt-account-id"] = accountId;
203
- const urls = [
204
- `${CHATGPT_BASE}/backend-api/me`,
205
- `${CHATGPT_BASE}/backend-api/conversations?offset=0&limit=28&order=updated`,
206
- `${CHATGPT_BASE}/backend-api/models?history_and_training_disabled=false`
207
- ];
208
- for (const url of urls) {
209
- try {
210
- const r = await tlsFetchChatGpt(url, {
211
- method: "GET",
212
- headers,
213
- timeoutMs: 15e3,
214
- signal
215
- });
216
- log?.debug?.("CGPT-WEB", `warmup ${url.split("/backend-api/")[1]} \u2192 ${r.status}`);
217
- } catch (err) {
218
- log?.debug?.(
219
- "CGPT-WEB",
220
- `warmup ${url} failed: ${err instanceof Error ? err.message : String(err)}`
221
- );
222
- }
223
- }
224
- }
225
- const thinkingEffortCache = /* @__PURE__ */ new Map();
226
- const THINKING_EFFORT_TTL_MS = 5 * 60 * 1e3;
227
- const THINKING_EFFORT_CACHE_MAX = 400;
228
- function configuredProPollTimeoutMs() {
229
- const raw = Number(process.env.OMNIROUTE_CGPT_WEB_PRO_TIMEOUT_MS);
230
- if (!Number.isFinite(raw) || raw <= 0) return DEFAULT_PRO_POLL_TIMEOUT_MS;
231
- return Math.floor(raw);
232
- }
233
- function configuredProPollIntervalMs() {
234
- const raw = Number(process.env.OMNIROUTE_CGPT_WEB_PRO_POLL_INTERVAL_MS);
235
- if (!Number.isFinite(raw) || raw <= 0) return DEFAULT_PRO_POLL_INTERVAL_MS;
236
- return Math.floor(raw);
237
- }
238
- async function setUserThinkingEffort(modelSlug, effort, accessToken, accountId, sessionId, deviceId, cookie, signal, log) {
239
- const cacheKey = `${cookieKey(cookie)}:${modelSlug}:${effort}`;
240
- const now = Date.now();
241
- const last = thinkingEffortCache.get(cacheKey);
242
- if (last && now - last < THINKING_EFFORT_TTL_MS) {
243
- log?.debug?.("CGPT-WEB", `thinking_effort cached (${modelSlug}=${effort}) \u2014 skip PATCH`);
244
- return;
245
- }
246
- if (thinkingEffortCache.size >= THINKING_EFFORT_CACHE_MAX && !thinkingEffortCache.has(cacheKey)) {
247
- const first = thinkingEffortCache.keys().next().value;
248
- if (first) thinkingEffortCache.delete(first);
249
- }
250
- const url = `${USER_LAST_USED_MODEL_CONFIG_URL}?model_slug=${encodeURIComponent(modelSlug)}&thinking_effort=${encodeURIComponent(effort)}`;
251
- const headers = {
252
- ...browserHeaders(),
253
- ...oaiHeaders(sessionId, deviceId),
254
- Accept: "application/json",
255
- Authorization: `Bearer ${accessToken}`,
256
- Cookie: buildSessionCookieHeader(cookie),
257
- Priority: "u=4"
258
- };
259
- if (accountId) headers["chatgpt-account-id"] = accountId;
260
- try {
261
- const r = await tlsFetchChatGpt(url, {
262
- method: "PATCH",
263
- headers,
264
- timeoutMs: 15e3,
265
- signal
266
- });
267
- if (r.status >= 400) {
268
- log?.warn?.(
269
- "CGPT-WEB",
270
- `thinking_effort PATCH ${r.status} for ${modelSlug}=${effort} (continuing)`
271
- );
272
- return;
273
- }
274
- thinkingEffortCache.set(cacheKey, now);
275
- log?.debug?.("CGPT-WEB", `thinking_effort PATCH OK (${modelSlug}=${effort})`);
276
- } catch (err) {
277
- log?.warn?.(
278
- "CGPT-WEB",
279
- `thinking_effort PATCH failed: ${err instanceof Error ? err.message : String(err)}`
280
- );
281
- }
282
- }
283
- async function prepareChatRequirements(accessToken, accountId, sessionId, deviceId, cookie, dplInfo, signal, log) {
284
- const config = buildPrekeyConfig(CHATGPT_USER_AGENT, dplInfo.dpl, dplInfo.scriptSrc);
285
- const prekey = await buildPrepareToken(config, log);
286
- const headers = {
287
- ...browserHeaders(),
288
- ...oaiHeaders(sessionId, deviceId),
289
- "Content-Type": "application/json",
290
- Authorization: `Bearer ${accessToken}`,
291
- Cookie: buildSessionCookieHeader(cookie),
292
- Priority: "u=1, i"
293
- };
294
- if (accountId) headers["chatgpt-account-id"] = accountId;
295
- const prepResp = await tlsFetchChatGpt(SENTINEL_PREPARE_URL, {
296
- method: "POST",
297
- headers,
298
- body: JSON.stringify({ p: prekey }),
299
- timeoutMs: 3e4,
300
- signal
301
- });
302
- if (prepResp.status === 401 || prepResp.status === 403) {
303
- throw new SentinelBlockedError(`Sentinel /prepare blocked (HTTP ${prepResp.status})`);
304
- }
305
- if (prepResp.status >= 400) {
306
- throw new Error(`Sentinel /prepare failed (HTTP ${prepResp.status})`);
307
- }
308
- let prepData = {};
309
- try {
310
- prepData = JSON.parse(prepResp.text || "{}");
311
- } catch {
312
- console.warn("[chatgpt-web] chat requirements prep JSON parse failed");
313
- }
314
- if (!prepData.prepare_token) {
315
- return prepData;
316
- }
317
- const crBody = { p: prekey, prepare_token: prepData.prepare_token };
318
- const crResp = await tlsFetchChatGpt(SENTINEL_CR_URL, {
319
- method: "POST",
320
- headers,
321
- body: JSON.stringify(crBody),
322
- timeoutMs: 3e4,
323
- signal
324
- });
325
- if (crResp.status === 401 || crResp.status === 403) {
326
- throw new SentinelBlockedError(`Sentinel /chat-requirements blocked (HTTP ${crResp.status})`);
327
- }
328
- if (crResp.status >= 400) {
329
- return prepData;
330
- }
331
- try {
332
- const crData = JSON.parse(crResp.text || "{}");
333
- return { ...crData, prepare_token: prepData.prepare_token };
334
- } catch {
335
- console.warn("[chatgpt-web] chat requirements response JSON parse failed");
336
- return prepData;
337
- }
338
- }
339
- class SentinelBlockedError extends Error {
340
- constructor(message) {
341
- super(message);
342
- this.name = "SentinelBlockedError";
343
- }
344
- }
345
- let dplCache = null;
346
- const DPL_TTL_MS = 60 * 60 * 1e3;
347
- async function fetchDpl(cookie, signal) {
348
- if (dplCache && Date.now() < dplCache.expiresAt) {
349
- return { dpl: dplCache.dpl, scriptSrc: dplCache.scriptSrc };
350
- }
351
- const headers = {
352
- ...browserHeaders(),
353
- Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
354
- Cookie: buildSessionCookieHeader(cookie)
355
- };
356
- const response = await tlsFetchChatGpt(`${CHATGPT_BASE}/`, {
357
- method: "GET",
358
- headers,
359
- timeoutMs: 2e4,
360
- signal
361
- });
362
- const html = response.text || "";
363
- const dplMatch = html.match(/data-build="([^"]+)"/);
364
- const dpl = dplMatch ? `dpl=${dplMatch[1]}` : `dpl=${OAI_CLIENT_VERSION.replace(/^prod-/, "")}`;
365
- const scriptMatch = html.match(/<script[^>]+src="(https?:\/\/[^"]*\.js[^"]*)"/);
366
- const scriptSrc = scriptMatch?.[1] ?? `${CHATGPT_BASE}/_next/static/chunks/webpack-${randomHex(16)}.js`;
367
- dplCache = { dpl, scriptSrc, expiresAt: Date.now() + DPL_TTL_MS };
368
- return { dpl, scriptSrc };
369
- }
370
- function randomHex(n) {
371
- return randomBytes(Math.ceil(n / 2)).toString("hex").slice(0, n);
372
- }
373
- const NAVIGATOR_KEYS = [
374
- "webdriver\u2212false",
375
- "geolocation",
376
- "languages",
377
- "language",
378
- "platform",
379
- "userAgent",
380
- "vendor",
381
- "hardwareConcurrency",
382
- "deviceMemory",
383
- "permissions",
384
- "plugins",
385
- "mediaDevices"
386
- ];
387
- const DOCUMENT_KEYS = [
388
- "_reactListeningkfj3eavmks",
389
- "_reactListeningo743lnnpvdg",
390
- "location",
391
- "scrollingElement",
392
- "documentElement"
393
- ];
394
- const WINDOW_KEYS = [
395
- "webpackChunk_N_E",
396
- "__NEXT_DATA__",
397
- "chrome",
398
- "history",
399
- "screen",
400
- "navigation",
401
- "scrollX",
402
- "scrollY"
403
- ];
404
- function pick(arr) {
405
- return arr[Math.floor(Math.random() * arr.length)];
406
- }
407
- function buildPrekeyConfig(userAgent, dpl, scriptSrc) {
408
- const screenSizes = [3e3, 4e3, 3120, 4160];
409
- const cores = [8, 16, 24, 32];
410
- const dateStr = (/* @__PURE__ */ new Date()).toString();
411
- const perfNow = performance.now();
412
- const epochOffset = Date.now() - perfNow;
413
- return [
414
- pick(screenSizes),
415
- dateStr,
416
- 4294705152,
417
- 0,
418
- // mutated by solver
419
- userAgent,
420
- scriptSrc,
421
- dpl,
422
- "en-US",
423
- "en-US,en",
424
- 0,
425
- // mutated by solver
426
- pick(NAVIGATOR_KEYS),
427
- pick(DOCUMENT_KEYS),
428
- pick(WINDOW_KEYS),
429
- perfNow,
430
- randomUUID(),
431
- "",
432
- pick(cores),
433
- epochOffset
434
- ];
435
- }
436
- const POW_YIELD_EVERY = 1e3;
437
- function yieldToEventLoop() {
438
- return new Promise((resolve) => setImmediate(resolve));
439
- }
440
- async function solvePow(opts) {
441
- const cfg = [...opts.config];
442
- for (let i = 0; i < opts.maxIter; i++) {
443
- if (i > 0 && i % POW_YIELD_EVERY === 0) await yieldToEventLoop();
444
- cfg[3] = i;
445
- const json = JSON.stringify(cfg);
446
- const b642 = Buffer.from(json).toString("base64");
447
- const hash = sha3_512Hex(opts.seed + b642);
448
- if (opts.target && hash.slice(0, opts.target.length) <= opts.target) {
449
- return `${opts.prefix}${b642}`;
450
- }
451
- }
452
- opts.log?.warn?.(
453
- "CGPT-WEB",
454
- `PoW (${opts.label}) exhausted ${opts.maxIter} iterations against target=${opts.target || "<empty>"}; submitting unsolved token (Sentinel may reject)`
455
- );
456
- const b64 = Buffer.from(JSON.stringify(cfg)).toString("base64");
457
- return `${opts.prefix}${b64}`;
458
- }
459
- async function buildPrepareToken(config, log) {
460
- return solvePow({
461
- config,
462
- seed: "",
463
- target: "0fffff",
464
- prefix: "gAAAAAC",
465
- maxIter: 1e5,
466
- label: "prepare",
467
- log
468
- });
469
- }
470
- async function solveProofOfWork(seed, difficulty, config, log) {
471
- return solvePow({
472
- config,
473
- seed,
474
- target: (difficulty || "").toLowerCase(),
475
- prefix: "gAAAAAB",
476
- maxIter: 5e5,
477
- label: "conversation",
478
- log
479
- });
480
- }
481
- const DATA_URI_IMAGE_RE = /!\[([^\]]*)\]\(data:image\/[^)]+\)/g;
482
- const CACHED_IMAGE_URL_RE = /\/v1\/chatgpt-web\/image\/([a-f0-9]{16,64})(?=[)\s"'<>]|$)/gi;
483
- function stripInlinedImages(content) {
484
- return content.replace(
485
- DATA_URI_IMAGE_RE,
486
- (_, alt) => alt ? `[${alt}: generated image]` : "[generated image]"
487
- );
488
- }
489
- function findCachedImageContext(content) {
490
- let latest = null;
491
- for (const match of content.matchAll(CACHED_IMAGE_URL_RE)) {
492
- const id = match[1];
493
- const context = getChatGptImageConversationContext(id);
494
- if (context) latest = context;
495
- }
496
- return latest;
497
- }
498
- function parseOpenAIMessages(messages) {
499
- let systemMsg = "";
500
- const history = [];
501
- let latestImageContext = null;
502
- for (const msg of messages) {
503
- let role = String(msg.role || "user");
504
- if (role === "developer") role = "system";
505
- let content = "";
506
- if (typeof msg.content === "string") {
507
- content = msg.content;
508
- } else if (Array.isArray(msg.content)) {
509
- content = msg.content.filter((c) => c.type === "text").map((c) => String(c.text || "")).join(" ");
510
- }
511
- content = stripInlinedImages(content);
512
- const imageContext = findCachedImageContext(content);
513
- if (imageContext) latestImageContext = imageContext;
514
- if (!content.trim()) continue;
515
- if (role === "system") {
516
- systemMsg += (systemMsg ? "\n" : "") + content;
517
- } else if (role === "user" || role === "assistant") {
518
- history.push({ role, content });
519
- }
520
- }
521
- let currentMsg = "";
522
- if (history.length > 0 && history[history.length - 1].role === "user") {
523
- currentMsg = history.pop().content;
524
- }
525
- return { systemMsg, history, currentMsg, latestImageContext };
526
- }
527
- const IMAGE_GEN_REGEXES = [
528
- // verb + (anything within 40 chars) + image-noun
529
- /\b(?:generate|create|make|draw|paint|render|produce|design|sketch|illustrate|show me)\b[\s\S]{0,40}\b(?:image|picture|photo|photograph|drawing|illustration|sketch|painting|portrait|logo|icon|art|artwork|wallpaper|render|graphic)\b/i,
530
- // image-noun + "of" — "image of a kitten", "picture of mountains"
531
- /\b(?:image|picture|photo|photograph|illustration|drawing|painting|render)\s+of\b/i,
532
- // direct verb + a/an article — "draw a kitten", "paint an apple"
533
- /\b(?:draw|paint|sketch|render|illustrate)\s+(?:me\s+)?(?:a|an|some|the)\s+\w+/i,
534
- // explicit slash command users sometimes type — "/imagine ..."
535
- /^\s*\/(?:image|imagine|img|draw|paint)\b/im
536
- ];
537
- const OPENWEBUI_TOOL_PROMPT_MARKERS = [
538
- /<chat_history>/i,
539
- /^### Task:/im,
540
- /\bJSON format:\s*\{/i,
541
- /\bfollow_?ups\b.*\barray of strings\b/i
542
- ];
543
- const OPENWEBUI_IMAGE_CONTEXT_MARKERS = [
544
- /<context>\s*The requested image has been (?:created|edited and created) by the system successfully/i,
545
- /<context>\s*The requested image has been edited and created and is now being shown to the user/i,
546
- /<context>\s*Image generation was attempted but failed/i
547
- ];
548
- function hasOpenWebUIImageContext(parsed) {
549
- return OPENWEBUI_IMAGE_CONTEXT_MARKERS.some((re) => re.test(parsed.systemMsg));
550
- }
551
- function looksLikeImageGenRequest(parsed) {
552
- const text = parsed.currentMsg.trim();
553
- if (!text) return false;
554
- if (OPENWEBUI_TOOL_PROMPT_MARKERS.some((re) => re.test(text))) return false;
555
- if (hasOpenWebUIImageContext(parsed)) return false;
556
- return IMAGE_GEN_REGEXES.some((re) => re.test(text));
557
- }
558
- const IMAGE_EDIT_REGEXES = [
559
- /\b(?:edit|adjust|modify|change|update|alter|revise|retouch|fix)\b[\s\S]{0,120}\b(?:it|image|picture|photo|lighting|background|style|color|colour|composition|scene|time of day)\b/i,
560
- /\b(?:make|turn|set|switch)\s+(?:it|the\s+(?:image|picture|photo|scene))\b[\s\S]{0,120}\b/i,
561
- /\b(?:add|remove|replace)\b[\s\S]{0,120}\b(?:it|image|picture|photo|background|sky|person|object|text|logo)\b/i,
562
- /\b(?:brighter|darker|night|daytime|time of day|sunset|sunrise|morning|evening|lighting|relight|background|style)\b/i,
563
- /^\s*(?:now|then|also)\b[\s\S]{0,120}\b(?:make|turn|change|adjust|add|remove|replace|edit)\b/i
564
- ];
565
- function looksLikeImageEditRequest(parsed) {
566
- if (!parsed.latestImageContext) return false;
567
- const text = parsed.currentMsg.trim();
568
- if (!text) return false;
569
- if (OPENWEBUI_TOOL_PROMPT_MARKERS.some((re) => re.test(text))) return false;
570
- if (hasOpenWebUIImageContext(parsed)) return false;
571
- return IMAGE_EDIT_REGEXES.some((re) => re.test(text));
572
- }
573
- function buildConversationBody(parsed, modelSlug, parentMessageId, options) {
574
- const systemParts = [];
575
- if (parsed.systemMsg.trim()) {
576
- systemParts.push(parsed.systemMsg.trim());
577
- }
578
- const continuation = options.continuation ?? null;
579
- if (!continuation && parsed.history.length > 0) {
580
- const formatted = parsed.history.map((h) => `${h.role === "assistant" ? "Assistant" : "User"}: ${h.content}`).join("\n\n");
581
- systemParts.push(
582
- `Prior conversation (for context \u2014 answer only the new user message below):
583
-
584
- ${formatted}`
585
- );
586
- }
587
- const messages = [];
588
- if (systemParts.length > 0) {
589
- messages.push({
590
- id: randomUUID(),
591
- author: { role: "system" },
592
- content: { content_type: "text", parts: [systemParts.join("\n\n")] }
593
- });
594
- }
595
- const currentUserContent = hasOpenWebUIImageContext(parsed) ? "Briefly acknowledge the image result described in the system context. Do not generate, edit, or request another image." : parsed.currentMsg || "";
596
- messages.push({
597
- id: randomUUID(),
598
- author: { role: "user" },
599
- content: { content_type: "text", parts: [currentUserContent] }
600
- });
601
- return {
602
- action: "next",
603
- messages,
604
- model: modelSlug,
605
- // Text-only API-style requests start fresh because clients replay full
606
- // history. Generated-image edits are the exception: ChatGPT needs the
607
- // original conversation node to adjust the actual image, not just a
608
- // markdown URL echoed back in a synthetic history block.
609
- conversation_id: continuation?.conversationId ?? null,
610
- parent_message_id: continuation?.parentMessageId ?? parentMessageId,
611
- timezone_offset_min: -(/* @__PURE__ */ new Date()).getTimezoneOffset(),
612
- // Temporary Chat is the default. Disable it only for image generation /
613
- // image edits, where ChatGPT needs durable conversation state for tools.
614
- history_and_training_disabled: !options.persistConversation,
615
- suggestions: [],
616
- websocket_request_id: randomUUID(),
617
- conversation_mode: { kind: "primary_assistant" },
618
- supports_buffering: true,
619
- force_parallel_switch: "auto",
620
- paragen_cot_summary_display_override: "allow",
621
- ...options.thinkingEffort ? { thinking_effort: options.thinkingEffort } : {}
622
- };
623
- }
624
- async function* readChatGptSseEvents(body, signal) {
625
- const reader = body.getReader();
626
- const decoder = new TextDecoder();
627
- let buffer = "";
628
- let dataLines = [];
629
- let eventName = null;
630
- function flush() {
631
- if (dataLines.length === 0) {
632
- eventName = null;
633
- return null;
634
- }
635
- const payload = dataLines.join("\n");
636
- dataLines = [];
637
- const sseEventName = eventName;
638
- eventName = null;
639
- const trimmed = payload.trim();
640
- if (!trimmed || trimmed === "[DONE]") return "done";
641
- try {
642
- const parsed = JSON.parse(trimmed);
643
- if (sseEventName && !parsed.type) parsed.type = sseEventName;
644
- return parsed;
645
- } catch {
646
- console.warn("[chatgpt-web] stream event JSON parse failed");
647
- return null;
648
- }
649
- }
650
- try {
651
- while (true) {
652
- if (signal?.aborted) return;
653
- const { value, done } = await reader.read();
654
- if (done) break;
655
- buffer += decoder.decode(value, { stream: true });
656
- while (true) {
657
- const idx = buffer.indexOf("\n");
658
- if (idx < 0) break;
659
- const rawLine = buffer.slice(0, idx);
660
- buffer = buffer.slice(idx + 1);
661
- const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
662
- if (line === "") {
663
- const parsed = flush();
664
- if (parsed === "done") return;
665
- if (parsed) yield parsed;
666
- continue;
667
- }
668
- if (line.startsWith("event:")) {
669
- eventName = line.slice(6).trim();
670
- } else if (line.startsWith("data:")) {
671
- dataLines.push(line.slice(5).trimStart());
672
- }
673
- }
674
- }
675
- buffer += decoder.decode();
676
- if (buffer.trim().startsWith("data:")) {
677
- dataLines.push(buffer.trim().slice(5).trimStart());
678
- }
679
- const tail = flush();
680
- if (tail && tail !== "done") yield tail;
681
- } finally {
682
- reader.releaseLock();
683
- }
684
- }
685
- function extractImagePointers(parts) {
686
- const out = [];
687
- for (const p of parts) {
688
- if (!p || typeof p !== "object") continue;
689
- const obj = p;
690
- if (obj.content_type === "image_asset_pointer" && typeof obj.asset_pointer === "string") {
691
- out.push(obj.asset_pointer);
692
- }
693
- }
694
- return out;
695
- }
696
- async function* extractContent(eventStream, signal) {
697
- let conversationId = null;
698
- let currentId = null;
699
- let currentParts = "";
700
- let emittedLen = 0;
701
- let isLive = false;
702
- const imagePointers = /* @__PURE__ */ new Map();
703
- let imageGenAsync = false;
704
- let handoff = false;
705
- for await (const event of readChatGptSseEvents(eventStream, signal)) {
706
- if (event.error) {
707
- const msg = typeof event.error === "string" ? event.error : event.error.message || "ChatGPT stream error";
708
- yield { error: msg, done: true };
709
- return;
710
- }
711
- if (event.conversation_id) conversationId = event.conversation_id;
712
- if (event.type === "stream_handoff") {
713
- handoff = true;
714
- yield {
715
- conversationId: conversationId ?? void 0,
716
- handoff: true
717
- };
718
- continue;
719
- }
720
- if (event.type === "server_ste_metadata") {
721
- const meta = event.metadata;
722
- if (meta && meta.turn_use_case === "image gen") {
723
- imageGenAsync = true;
724
- }
725
- }
726
- const m = event.message;
727
- if (!m) continue;
728
- if (m.metadata && typeof m.metadata.image_gen_task_id === "string") {
729
- imageGenAsync = true;
730
- }
731
- if (m.author?.role !== "assistant") continue;
732
- const id = m.id ?? null;
733
- const status = m.status ?? "";
734
- if (id && id !== currentId) {
735
- currentId = id;
736
- currentParts = "";
737
- emittedLen = 0;
738
- isLive = false;
739
- }
740
- if (status === "in_progress") {
741
- isLive = true;
742
- }
743
- const parts = m.content?.parts ?? [];
744
- if (parts.length === 0) continue;
745
- if (status === "finished_successfully" || status === "" || isLive) {
746
- for (const ptr of extractImagePointers(parts)) {
747
- const existing = imagePointers.get(ptr);
748
- imagePointers.set(
749
- ptr,
750
- existing?.messageId ? existing : { pointer: ptr, ...id ? { messageId: id } : {} }
751
- );
752
- }
753
- }
754
- const cumulative = parts.map((p) => typeof p === "string" ? p : "").join("");
755
- if (cumulative.length > currentParts.length) {
756
- currentParts = cumulative;
757
- }
758
- if (isLive && currentParts.length > emittedLen) {
759
- const delta = currentParts.slice(emittedLen);
760
- emittedLen = currentParts.length;
761
- yield {
762
- delta,
763
- answer: currentParts,
764
- conversationId: conversationId ?? void 0,
765
- messageId: currentId ?? void 0
766
- };
767
- }
768
- }
769
- if (!isLive && currentParts.length > emittedLen) {
770
- yield {
771
- delta: currentParts.slice(emittedLen),
772
- answer: currentParts,
773
- conversationId: conversationId ?? void 0,
774
- messageId: currentId ?? void 0
775
- };
776
- }
777
- yield {
778
- delta: "",
779
- answer: currentParts,
780
- conversationId: conversationId ?? void 0,
781
- messageId: currentId ?? void 0,
782
- imagePointers: imagePointers.size > 0 ? Array.from(imagePointers.values()) : void 0,
783
- imageGenAsync,
784
- handoff,
785
- done: true
786
- };
787
- }
788
- function textFromContentPart(part) {
789
- if (typeof part === "string") return part;
790
- if (!part || typeof part !== "object") return "";
791
- const obj = part;
792
- for (const key of ["text", "content", "summary"]) {
793
- const value = obj[key];
794
- if (typeof value === "string") return value;
795
- }
796
- return "";
797
- }
798
- function detailMessageText(message) {
799
- const content = message.content;
800
- if (!content) return "";
801
- if (typeof content.text === "string") return content.text;
802
- const parts = content.parts ?? [];
803
- return parts.map(textFromContentPart).join("");
804
- }
805
- function extractFinalAssistantAnswer(detail) {
806
- const nodes = Object.values(detail.mapping ?? {});
807
- let best = null;
808
- for (const node of nodes) {
809
- const message = node.message;
810
- if (!message || message.author?.role !== "assistant") continue;
811
- if (message.metadata?.is_visually_hidden === true) continue;
812
- const contentType = message.content?.content_type ?? "";
813
- if (contentType.includes("thought") || contentType.includes("reasoning")) continue;
814
- const text = detailMessageText(message).trim();
815
- if (!text) continue;
816
- const finished = message.status === "finished_successfully" && message.end_turn !== false;
817
- const sort = message.update_time ?? message.create_time ?? 0;
818
- if (!best || finished && (!best.finished || sort >= best.sort) || !finished && !best.finished && sort >= best.sort) {
819
- best = { text, messageId: message.id, finished, sort };
820
- }
821
- }
822
- if (!best) return null;
823
- return { text: best.text, messageId: best.messageId, finished: best.finished };
824
- }
825
- function delayWithAbort(ms, signal) {
826
- if (ms <= 0) return Promise.resolve();
827
- if (signal?.aborted) return Promise.resolve();
828
- return new Promise((resolve) => {
829
- const timer = setTimeout(() => {
830
- signal?.removeEventListener("abort", onAbort);
831
- resolve();
832
- }, ms);
833
- const onAbort = () => {
834
- clearTimeout(timer);
835
- signal?.removeEventListener("abort", onAbort);
836
- resolve();
837
- };
838
- signal?.addEventListener("abort", onAbort, { once: true });
839
- });
840
- }
841
- function decodeUtf8DataUrl(text) {
842
- const marker = ";base64,";
843
- if (!text.startsWith("data:") || !text.includes(marker)) return text;
844
- const base64 = text.slice(text.indexOf(marker) + marker.length);
845
- return new TextDecoder().decode(Buffer.from(base64, "base64"));
846
- }
847
- async function fetchConversationDetail(conversationId, ctx) {
848
- const url = `${CHATGPT_BASE}/backend-api/conversation/${encodeURIComponent(conversationId)}`;
849
- const headers = {
850
- ...browserHeaders(),
851
- ...oaiHeaders(ctx.sessionId, ctx.deviceId),
852
- Accept: "application/json",
853
- Authorization: `Bearer ${ctx.accessToken}`,
854
- Cookie: buildSessionCookieHeader(ctx.cookie)
855
- };
856
- if (ctx.accountId) headers["chatgpt-account-id"] = ctx.accountId;
857
- try {
858
- const response = await tlsFetchChatGpt(url, {
859
- method: "GET",
860
- headers,
861
- timeoutMs: 3e4,
862
- signal: ctx.signal,
863
- // The native tls-client text path can surface UTF-8 JSON as mojibake
864
- // (e.g. 👉 becomes 👉). Ask for raw bytes and decode as UTF-8 here so
865
- // the final answer appended after Pro stream_handoff preserves Unicode.
866
- byteResponse: true
867
- });
868
- if (response.status >= 400) {
869
- ctx.log?.warn?.(
870
- "CGPT-WEB",
871
- `conversation poll ${response.status}: ${(response.text || "").slice(0, 300)}`
872
- );
873
- return { detail: null, terminal: [401, 403, 404].includes(response.status) };
874
- }
875
- if (!response.text) return { detail: null, terminal: false };
876
- return {
877
- detail: JSON.parse(decodeUtf8DataUrl(response.text)),
878
- terminal: false
879
- };
880
- } catch (err) {
881
- ctx.log?.warn?.(
882
- "CGPT-WEB",
883
- `conversation poll failed: ${err instanceof Error ? err.message : String(err)}`
884
- );
885
- return { detail: null, terminal: false };
886
- }
887
- }
888
- async function pollForFinalAssistantAnswer(conversationId, ctx) {
889
- const started = Date.now();
890
- const timeoutMs = configuredProPollTimeoutMs();
891
- const intervalMs = configuredProPollIntervalMs();
892
- let last = null;
893
- let terminalPollFailure = false;
894
- while (!ctx.signal?.aborted && Date.now() - started < timeoutMs) {
895
- const { detail, terminal } = await fetchConversationDetail(conversationId, ctx);
896
- if (detail) {
897
- const answer = extractFinalAssistantAnswer(detail);
898
- if (answer) {
899
- last = answer;
900
- if (answer.finished) return answer;
901
- }
902
- }
903
- if (terminal) {
904
- terminalPollFailure = true;
905
- break;
906
- }
907
- const remaining = timeoutMs - (Date.now() - started);
908
- if (remaining <= 0) break;
909
- await delayWithAbort(Math.min(intervalMs, remaining), ctx.signal);
910
- }
911
- if (last) {
912
- ctx.log?.warn?.(
913
- "CGPT-WEB",
914
- terminalPollFailure ? `conversation poll stopped before finished_successfully; returning latest assistant text for ${conversationId}` : `conversation poll timed out before finished_successfully; returning latest assistant text for ${conversationId}`
915
- );
916
- } else {
917
- ctx.log?.warn?.(
918
- "CGPT-WEB",
919
- terminalPollFailure ? `conversation poll stopped without assistant text for ${conversationId}` : `conversation poll timed out without assistant text for ${conversationId}`
920
- );
921
- }
922
- return last;
923
- }
924
- function sseChunk(data) {
925
- return `data: ${JSON.stringify(data)}
926
-
927
- `;
928
- }
929
- function detectImageResolutionFailure(pointerCount, resolvedCount) {
930
- return pointerCount > 0 && resolvedCount === 0;
931
- }
932
- function imageMarkdown(urls) {
933
- if (urls.length === 0) return "";
934
- return "\n\n" + urls.map((u) => `![image](${u})`).join("\n\n");
935
- }
936
- async function resolveImagePointers(pointers, conversationId, resolver, log, fallbackParentMessageId) {
937
- if (!pointers || pointers.length === 0 || !resolver) return [];
938
- const urls = [];
939
- for (const ref of pointers) {
940
- try {
941
- const url = await resolver(
942
- ref.pointer,
943
- conversationId,
944
- ref.messageId ?? fallbackParentMessageId
945
- );
946
- if (url) urls.push(url);
947
- } catch (err) {
948
- log?.warn?.(
949
- "CGPT-WEB",
950
- `Image resolve failed (${ref.pointer}): ${err instanceof Error ? err.message : String(err)}`
951
- );
952
- }
953
- }
954
- return urls;
955
- }
956
- function buildStreamingResponse(eventStream, model, cid, created, resolver, pollAsyncImage, pollFinalAnswer, log, signal) {
957
- const encoder = new TextEncoder();
958
- return new ReadableStream(
959
- {
960
- async start(controller) {
961
- try {
962
- controller.enqueue(
963
- encoder.encode(
964
- sseChunk({
965
- id: cid,
966
- object: "chat.completion.chunk",
967
- created,
968
- model,
969
- system_fingerprint: null,
970
- choices: [
971
- { index: 0, delta: { role: "assistant" }, finish_reason: null, logprobs: null }
972
- ]
973
- })
974
- )
975
- );
976
- let conversationId = null;
977
- let imagePointers;
978
- let imageGenAsync = false;
979
- let handoff = false;
980
- let emittedText = "";
981
- let polledFinalAnswer = "";
982
- let parentCandidateMessageId = null;
983
- const emitTextDelta = (content) => {
984
- const cleaned = cleanChatGptText(content);
985
- if (!cleaned) return;
986
- emittedText += cleaned;
987
- controller.enqueue(
988
- encoder.encode(
989
- sseChunk({
990
- id: cid,
991
- object: "chat.completion.chunk",
992
- created,
993
- model,
994
- system_fingerprint: null,
995
- choices: [
996
- {
997
- index: 0,
998
- delta: { content: cleaned },
999
- finish_reason: null,
1000
- logprobs: null
1001
- }
1002
- ]
1003
- })
1004
- )
1005
- );
1006
- };
1007
- const appendFinalAnswer = (text) => {
1008
- const cleaned = cleanChatGptText(text);
1009
- const finalTrimmed = cleaned.trim();
1010
- if (!finalTrimmed) return;
1011
- const emittedTrimmed = emittedText.trim();
1012
- if (emittedTrimmed === finalTrimmed || emittedTrimmed.endsWith(finalTrimmed)) return;
1013
- const prefix = emittedTrimmed && !emittedText.endsWith("\n") ? "\n\n" : "";
1014
- emitTextDelta(`${prefix}${cleaned}`);
1015
- };
1016
- const startHeartbeat = (intervalMs = 5e3) => {
1017
- const heartbeatChunk = sseChunk({
1018
- id: cid,
1019
- object: "chat.completion.chunk",
1020
- created,
1021
- model,
1022
- system_fingerprint: null,
1023
- choices: [{ index: 0, delta: { content: "\u200B" }, finish_reason: null, logprobs: null }]
1024
- });
1025
- const timer = setInterval(() => {
1026
- try {
1027
- controller.enqueue(encoder.encode(heartbeatChunk));
1028
- } catch {
1029
- console.warn("[chatgpt-web] heartbeat enqueue failed - controller closed");
1030
- clearInterval(timer);
1031
- }
1032
- }, intervalMs);
1033
- return () => clearInterval(timer);
1034
- };
1035
- for await (const chunk of extractContent(eventStream, signal)) {
1036
- if (chunk.conversationId) conversationId = chunk.conversationId;
1037
- if (chunk.messageId) parentCandidateMessageId = chunk.messageId;
1038
- if (chunk.handoff) handoff = true;
1039
- if (chunk.error) {
1040
- controller.enqueue(
1041
- encoder.encode(
1042
- sseChunk({
1043
- id: cid,
1044
- object: "chat.completion.chunk",
1045
- created,
1046
- model,
1047
- system_fingerprint: null,
1048
- choices: [
1049
- {
1050
- index: 0,
1051
- delta: { content: `[Error: ${chunk.error}]` },
1052
- finish_reason: null,
1053
- logprobs: null
1054
- }
1055
- ]
1056
- })
1057
- )
1058
- );
1059
- break;
1060
- }
1061
- if (chunk.done) {
1062
- imagePointers = chunk.imagePointers;
1063
- imageGenAsync = chunk.imageGenAsync ?? false;
1064
- handoff = handoff || (chunk.handoff ?? false);
1065
- if (chunk.messageId) parentCandidateMessageId = chunk.messageId;
1066
- break;
1067
- }
1068
- if (chunk.delta) {
1069
- emitTextDelta(chunk.delta);
1070
- }
1071
- }
1072
- if (pollFinalAnswer && conversationId && handoff) {
1073
- const stopHb = startHeartbeat();
1074
- try {
1075
- const polled = await pollFinalAnswer(conversationId);
1076
- if (polled?.text) {
1077
- polledFinalAnswer = polled.text;
1078
- if (polled.messageId) parentCandidateMessageId = polled.messageId;
1079
- }
1080
- } finally {
1081
- stopHb();
1082
- }
1083
- }
1084
- if (polledFinalAnswer) {
1085
- appendFinalAnswer(polledFinalAnswer);
1086
- }
1087
- if (imageGenAsync && conversationId && (!imagePointers || imagePointers.length === 0) && pollAsyncImage) {
1088
- controller.enqueue(
1089
- encoder.encode(
1090
- sseChunk({
1091
- id: cid,
1092
- object: "chat.completion.chunk",
1093
- created,
1094
- model,
1095
- system_fingerprint: null,
1096
- choices: [
1097
- {
1098
- index: 0,
1099
- delta: { content: "_Generating image\u2026_\n\n" },
1100
- finish_reason: null,
1101
- logprobs: null
1102
- }
1103
- ]
1104
- })
1105
- )
1106
- );
1107
- const stopHb = startHeartbeat();
1108
- try {
1109
- const polled = await pollAsyncImage(conversationId);
1110
- if (polled.length > 0) imagePointers = polled;
1111
- } catch (err) {
1112
- log?.warn?.(
1113
- "CGPT-WEB",
1114
- `Async image poll failed: ${err instanceof Error ? err.message : String(err)}`
1115
- );
1116
- } finally {
1117
- stopHb();
1118
- }
1119
- }
1120
- const stopHb2 = startHeartbeat();
1121
- let urls = [];
1122
- try {
1123
- urls = await resolveImagePointers(
1124
- imagePointers,
1125
- conversationId,
1126
- resolver,
1127
- log,
1128
- parentCandidateMessageId
1129
- );
1130
- } finally {
1131
- stopHb2();
1132
- }
1133
- if (signal?.aborted) return;
1134
- const mdBlock = imageMarkdown(urls);
1135
- const safeEnqueue = (bytes) => {
1136
- try {
1137
- controller.enqueue(bytes);
1138
- return true;
1139
- } catch {
1140
- console.warn("[chatgpt-web] controller enqueue failed");
1141
- return false;
1142
- }
1143
- };
1144
- if (mdBlock) {
1145
- if (!safeEnqueue(
1146
- encoder.encode(
1147
- sseChunk({
1148
- id: cid,
1149
- object: "chat.completion.chunk",
1150
- created,
1151
- model,
1152
- system_fingerprint: null,
1153
- choices: [
1154
- {
1155
- index: 0,
1156
- delta: { content: mdBlock },
1157
- finish_reason: null,
1158
- logprobs: null
1159
- }
1160
- ]
1161
- })
1162
- )
1163
- ))
1164
- return;
1165
- }
1166
- if (!safeEnqueue(
1167
- encoder.encode(
1168
- sseChunk({
1169
- id: cid,
1170
- object: "chat.completion.chunk",
1171
- created,
1172
- model,
1173
- system_fingerprint: null,
1174
- choices: [{ index: 0, delta: {}, finish_reason: "stop", logprobs: null }]
1175
- })
1176
- )
1177
- ))
1178
- return;
1179
- safeEnqueue(encoder.encode("data: [DONE]\n\n"));
1180
- } catch (err) {
1181
- controller.enqueue(
1182
- encoder.encode(
1183
- sseChunk({
1184
- id: cid,
1185
- object: "chat.completion.chunk",
1186
- created,
1187
- model,
1188
- system_fingerprint: null,
1189
- choices: [
1190
- {
1191
- index: 0,
1192
- delta: {
1193
- content: `[Stream error: ${err instanceof Error ? err.message : String(err)}]`
1194
- },
1195
- finish_reason: "stop",
1196
- logprobs: null
1197
- }
1198
- ]
1199
- })
1200
- )
1201
- );
1202
- controller.enqueue(encoder.encode("data: [DONE]\n\n"));
1203
- } finally {
1204
- try {
1205
- controller.close();
1206
- } catch {
1207
- }
1208
- }
1209
- }
1210
- },
1211
- { highWaterMark: 16384 }
1212
- );
1213
- }
1214
- async function buildNonStreamingResponse(eventStream, model, cid, created, currentMsg, resolver, pollAsyncImage, pollFinalAnswer, log, signal) {
1215
- let fullAnswer = "";
1216
- let conversationId = null;
1217
- let imagePointers;
1218
- let imageGenAsync = false;
1219
- let handoff = false;
1220
- let parentCandidateMessageId = null;
1221
- for await (const chunk of extractContent(eventStream, signal)) {
1222
- if (chunk.conversationId) conversationId = chunk.conversationId;
1223
- if (chunk.messageId) parentCandidateMessageId = chunk.messageId;
1224
- if (chunk.handoff) handoff = true;
1225
- if (chunk.error) {
1226
- return new Response(
1227
- JSON.stringify({
1228
- error: { message: chunk.error, type: "upstream_error", code: "CHATGPT_ERROR" }
1229
- }),
1230
- { status: 502, headers: { "Content-Type": "application/json" } }
1231
- );
1232
- }
1233
- if (chunk.done) {
1234
- fullAnswer = chunk.answer || fullAnswer;
1235
- imagePointers = chunk.imagePointers;
1236
- imageGenAsync = chunk.imageGenAsync ?? false;
1237
- handoff = handoff || (chunk.handoff ?? false);
1238
- if (chunk.messageId) parentCandidateMessageId = chunk.messageId;
1239
- break;
1240
- }
1241
- if (chunk.answer) fullAnswer = chunk.answer;
1242
- }
1243
- if (pollFinalAnswer && conversationId && (handoff || !fullAnswer.trim())) {
1244
- const polled = await pollFinalAnswer(conversationId);
1245
- if (polled?.text) {
1246
- fullAnswer = polled.text;
1247
- if (polled.messageId) parentCandidateMessageId = polled.messageId;
1248
- }
1249
- }
1250
- fullAnswer = cleanChatGptText(fullAnswer);
1251
- if (imageGenAsync && conversationId && (!imagePointers || imagePointers.length === 0) && pollAsyncImage) {
1252
- try {
1253
- const polled = await pollAsyncImage(conversationId);
1254
- if (polled.length > 0) imagePointers = polled;
1255
- } catch (err) {
1256
- log?.warn?.(
1257
- "CGPT-WEB",
1258
- `Async image poll failed: ${err instanceof Error ? err.message : String(err)}`
1259
- );
1260
- }
1261
- }
1262
- const urls = await resolveImagePointers(
1263
- imagePointers,
1264
- conversationId,
1265
- resolver,
1266
- log,
1267
- parentCandidateMessageId
1268
- );
1269
- const imageResolutionFailed = detectImageResolutionFailure(
1270
- imagePointers?.length ?? 0,
1271
- urls.length
1272
- );
1273
- if (imageResolutionFailed && log?.warn) {
1274
- const schemes = (imagePointers ?? []).map((p) => p.pointer.split("://")[0] || p.pointer.slice(0, 24)).join(", ");
1275
- log.warn(
1276
- "CGPT-WEB",
1277
- `Image generated upstream but no asset pointer resolved (schemes: ${schemes}) \u2014 surfacing as unretrievable`
1278
- );
1279
- }
1280
- fullAnswer += imageMarkdown(urls);
1281
- const promptTokens = Math.ceil(currentMsg.length / 4);
1282
- const completionTokens = Math.ceil(fullAnswer.length / 4);
1283
- return new Response(
1284
- JSON.stringify({
1285
- id: cid,
1286
- object: "chat.completion",
1287
- created,
1288
- model,
1289
- system_fingerprint: null,
1290
- ...imageResolutionFailed ? { x_image_resolution_failed: true } : {},
1291
- choices: [
1292
- {
1293
- index: 0,
1294
- message: { role: "assistant", content: fullAnswer },
1295
- finish_reason: "stop",
1296
- logprobs: null
1297
- }
1298
- ],
1299
- usage: {
1300
- prompt_tokens: promptTokens,
1301
- completion_tokens: completionTokens,
1302
- total_tokens: promptTokens + completionTokens
1303
- }
1304
- }),
1305
- { status: 200, headers: { "Content-Type": "application/json" } }
1306
- );
1307
- }
1308
- function errorResponse(status, message, code) {
1309
- return new Response(
1310
- JSON.stringify({ error: { message, type: "upstream_error", ...code ? { code } : {} } }),
1311
- { status, headers: { "Content-Type": "application/json" } }
1312
- );
1313
- }
1314
- function normalizePublicBaseUrl(value) {
1315
- const trimmed = value?.trim();
1316
- if (!trimmed) return null;
1317
- return trimmed.replace(/\/+$/, "").replace(/\/v1$/i, "");
1318
- }
1319
- function firstForwardedValue(value) {
1320
- const first = value?.split(",")[0]?.trim();
1321
- return first || null;
1322
- }
1323
- function isLocalBaseUrl(baseUrl) {
1324
- try {
1325
- const host = new URL(baseUrl).hostname.toLowerCase();
1326
- return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0";
1327
- } catch {
1328
- console.warn("[chatgpt-web] URL parse failed, falling back to regex");
1329
- return /\b(?:localhost|127\.0\.0\.1|0\.0\.0\.0)\b/i.test(baseUrl);
1330
- }
1331
- }
1332
- function deriveHeaderBaseUrl(clientHeaders) {
1333
- const headers = clientHeaders ?? {};
1334
- const lower = {};
1335
- for (const [k, v] of Object.entries(headers)) lower[k.toLowerCase()] = v;
1336
- const forwardedHost = firstForwardedValue(lower["x-forwarded-host"]);
1337
- const forwardedProto = firstForwardedValue(lower["x-forwarded-proto"]);
1338
- const host = forwardedHost || firstForwardedValue(lower["host"]);
1339
- if (!host) return null;
1340
- const isPlain = host.includes("localhost") || /^\d+\.\d+\.\d+\.\d+(:\d+)?$/.test(host) || host.endsWith(".local") || host.includes(":");
1341
- const proto = forwardedProto || (isPlain ? "http" : "https");
1342
- return `${proto}://${host}`;
1343
- }
1344
- function derivePublicBaseUrl(clientHeaders, log) {
1345
- const explicitPublicBase = normalizePublicBaseUrl(process.env.OMNIROUTE_PUBLIC_BASE_URL);
1346
- if (explicitPublicBase) {
1347
- log?.debug?.("CGPT-WEB", `derivePublicBaseUrl: using OMNIROUTE_PUBLIC_BASE_URL`);
1348
- return explicitPublicBase;
1349
- }
1350
- const headerBase = deriveHeaderBaseUrl(clientHeaders);
1351
- const configuredBase = normalizePublicBaseUrl(process.env.OMNIROUTE_BASE_URL) || normalizePublicBaseUrl(process.env.NEXT_PUBLIC_BASE_URL);
1352
- log?.debug?.(
1353
- "CGPT-WEB",
1354
- `derivePublicBaseUrl: configured=${configuredBase ?? "-"} header=${headerBase ?? "-"}`
1355
- );
1356
- if (configuredBase && (!headerBase || !isLocalBaseUrl(configuredBase))) return configuredBase;
1357
- if (headerBase) return headerBase;
1358
- if (configuredBase) return configuredBase;
1359
- return `http://localhost:${process.env.PORT || 20128}`;
1360
- }
1361
- const FILE_SERVICE_PREFIX = "file-service://";
1362
- const SEDIMENT_PREFIX = "sediment://";
1363
- async function fetchDownloadUrl(endpoint, ctx) {
1364
- const headers = {
1365
- ...browserHeaders(),
1366
- ...oaiHeaders(ctx.sessionId, ctx.deviceId),
1367
- Accept: "application/json",
1368
- Authorization: `Bearer ${ctx.accessToken}`,
1369
- Cookie: buildSessionCookieHeader(ctx.cookie)
1370
- };
1371
- if (ctx.accountId) headers["chatgpt-account-id"] = ctx.accountId;
1372
- const response = await tlsFetchChatGpt(endpoint, {
1373
- method: "GET",
1374
- headers,
1375
- timeoutMs: 3e4,
1376
- signal: ctx.signal
1377
- });
1378
- if (response.status !== 200) {
1379
- ctx.log?.warn?.(
1380
- "CGPT-WEB",
1381
- `Image download URL fetch failed (${response.status}) for ${endpoint}`
1382
- );
1383
- return null;
1384
- }
1385
- let parsed = {};
1386
- try {
1387
- parsed = JSON.parse(response.text || "{}");
1388
- } catch {
1389
- console.warn("[chatgpt-web] image download URL parse failed");
1390
- return null;
1391
- }
1392
- return parsed.download_url ?? null;
1393
- }
1394
- const IMAGE_DOWNLOAD_MAX_BYTES = 8 * 1024 * 1024;
1395
- async function imageUrlToCachedImageUrl(signedUrl, ctx, imageContext) {
1396
- const headers = {
1397
- ...browserHeaders(),
1398
- Accept: "image/*,*/*;q=0.8",
1399
- Authorization: `Bearer ${ctx.accessToken}`,
1400
- Cookie: buildSessionCookieHeader(ctx.cookie)
1401
- };
1402
- if (ctx.accountId) headers["chatgpt-account-id"] = ctx.accountId;
1403
- let response;
1404
- try {
1405
- response = await tlsFetchChatGpt(signedUrl, {
1406
- method: "GET",
1407
- headers,
1408
- timeoutMs: 6e4,
1409
- signal: ctx.signal,
1410
- // Required for binary payloads — the underlying tls-client returns
1411
- // bytes as a `data:<mime>;base64,...` string when this is true.
1412
- // Without it, raw image bytes get mangled by UTF-8 decoding.
1413
- byteResponse: true
1414
- });
1415
- } catch (err) {
1416
- ctx.log?.warn?.(
1417
- "CGPT-WEB",
1418
- `Image fetch failed: ${err instanceof Error ? err.message : String(err)}`
1419
- );
1420
- return null;
1421
- }
1422
- if (response.status !== 200) {
1423
- ctx.log?.warn?.(
1424
- "CGPT-WEB",
1425
- `Image fetch returned HTTP ${response.status} (${(response.text || "").slice(0, 120)})`
1426
- );
1427
- return null;
1428
- }
1429
- if (response.text == null || response.text.length === 0) return null;
1430
- let bytes;
1431
- let mime;
1432
- if (/^data:[^;]{1,256};base64,/.test(response.text)) {
1433
- const commaIdx = response.text.indexOf(",");
1434
- const header = response.text.slice(5, commaIdx);
1435
- mime = header.split(";")[0] || "image/png";
1436
- bytes = Buffer.from(response.text.slice(commaIdx + 1), "base64");
1437
- } else {
1438
- bytes = Buffer.from(response.text, "binary");
1439
- mime = response.headers.get("content-type")?.split(";")[0]?.trim() || "image/png";
1440
- }
1441
- if (bytes.length === 0 || bytes.length > IMAGE_DOWNLOAD_MAX_BYTES) {
1442
- if (bytes.length > IMAGE_DOWNLOAD_MAX_BYTES) {
1443
- ctx.log?.warn?.(
1444
- "CGPT-WEB",
1445
- `Image too large to cache (${bytes.length} bytes > ${IMAGE_DOWNLOAD_MAX_BYTES}); skipping`
1446
- );
1447
- }
1448
- return null;
1449
- }
1450
- const id = storeChatGptImage(bytes, mime, void 0, imageContext);
1451
- return `${ctx.publicBaseUrl}/v1/chatgpt-web/image/${id}`;
1452
- }
1453
- async function registerWebSocket(ctx) {
1454
- const candidates = [
1455
- { url: `${CHATGPT_BASE}/backend-api/celsius/ws/user`, method: "GET" },
1456
- { url: `${CHATGPT_BASE}/backend-api/register-websocket`, method: "POST" }
1457
- ];
1458
- const headers = {
1459
- ...browserHeaders(),
1460
- ...oaiHeaders(ctx.sessionId, ctx.deviceId),
1461
- Accept: "application/json",
1462
- Authorization: `Bearer ${ctx.accessToken}`,
1463
- Cookie: buildSessionCookieHeader(ctx.cookie)
1464
- };
1465
- if (ctx.accountId) headers["chatgpt-account-id"] = ctx.accountId;
1466
- for (const { url, method } of candidates) {
1467
- let r;
1468
- try {
1469
- r = await tlsFetchChatGpt(url, {
1470
- method,
1471
- headers,
1472
- body: method === "POST" ? "" : void 0,
1473
- timeoutMs: 3e4,
1474
- signal: ctx.signal
1475
- });
1476
- } catch (err) {
1477
- ctx.log?.warn?.(
1478
- "CGPT-WEB",
1479
- `register-websocket fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`
1480
- );
1481
- continue;
1482
- }
1483
- if (r.status === 200) {
1484
- try {
1485
- const data = JSON.parse(r.text || "{}");
1486
- const ws = data.websocket_url ?? data.wss_url;
1487
- if (ws) {
1488
- ctx.log?.debug?.("CGPT-WEB", `Got WebSocket URL via ${url}`);
1489
- return ws;
1490
- }
1491
- } catch {
1492
- console.warn("[chatgpt-web] WebSocket URL parse failed, falling through");
1493
- }
1494
- }
1495
- ctx.log?.warn?.(
1496
- "CGPT-WEB",
1497
- `register-websocket via ${url} \u2192 ${r.status}: ${(r.text || "").slice(0, 200)}`
1498
- );
1499
- }
1500
- return null;
1501
- }
1502
- async function waitForImageViaWebSocket(wssUrl, conversationId, timeoutMs, ctx) {
1503
- return new Promise((resolve) => {
1504
- const found = /* @__PURE__ */ new Map();
1505
- let resolved = false;
1506
- let errored = false;
1507
- let gotAnyMessage = false;
1508
- const finish = () => {
1509
- if (resolved) return;
1510
- resolved = true;
1511
- try {
1512
- ws.close();
1513
- } catch {
1514
- console.warn("[chatgpt-web] ws.close failed");
1515
- }
1516
- resolve({
1517
- pointers: Array.from(found.values()),
1518
- errored,
1519
- gotAnyMessage
1520
- });
1521
- };
1522
- const ws = new WebSocket(wssUrl);
1523
- const timer = setTimeout(() => {
1524
- ctx.log?.warn?.("CGPT-WEB", `WebSocket image wait timed out after ${timeoutMs}ms`);
1525
- finish();
1526
- }, timeoutMs);
1527
- const onAbort = () => {
1528
- ctx.log?.debug?.("CGPT-WEB", "WebSocket aborted by client");
1529
- finish();
1530
- };
1531
- ctx.signal?.addEventListener?.("abort", onAbort);
1532
- ws.onopen = () => {
1533
- gotAnyMessage = true;
1534
- ctx.log?.debug?.("CGPT-WEB", "WebSocket open \u2014 waiting for image events");
1535
- };
1536
- ws.onerror = (e) => {
1537
- errored = true;
1538
- ctx.log?.warn?.("CGPT-WEB", `WebSocket error: ${e.message ?? "unknown"}`);
1539
- };
1540
- ws.onclose = () => {
1541
- clearTimeout(timer);
1542
- ctx.signal?.removeEventListener?.("abort", onAbort);
1543
- finish();
1544
- };
1545
- ws.onmessage = (event) => {
1546
- gotAnyMessage = true;
1547
- let payload;
1548
- const raw = typeof event.data === "string" ? event.data : event.data.toString();
1549
- try {
1550
- payload = JSON.parse(raw);
1551
- } catch {
1552
- console.warn("[chatgpt-web] WebSocket event JSON parse failed");
1553
- return;
1554
- }
1555
- const obj = payload;
1556
- const candidates = [];
1557
- const innerPayload = obj.payload;
1558
- const updateContent = innerPayload?.update_content;
1559
- if (updateContent?.message) {
1560
- candidates.push({
1561
- message: updateContent.message,
1562
- conversation_id: innerPayload?.conversation_id
1563
- });
1564
- }
1565
- if (innerPayload?.message) {
1566
- candidates.push({
1567
- message: innerPayload.message,
1568
- conversation_id: innerPayload.conversation_id
1569
- });
1570
- }
1571
- if (obj.data?.message) {
1572
- candidates.push(obj.data);
1573
- }
1574
- for (const data of candidates) {
1575
- if (data?.conversation_id && data.conversation_id !== conversationId) continue;
1576
- const m = data?.message;
1577
- if (Array.isArray(m?.content?.parts)) {
1578
- for (const ptr of extractImagePointers(m.content?.parts ?? [])) {
1579
- const existing = found.get(ptr);
1580
- found.set(
1581
- ptr,
1582
- existing?.messageId ? existing : { pointer: ptr, ...m?.id ? { messageId: m.id } : {} }
1583
- );
1584
- }
1585
- }
1586
- if (m?.metadata && typeof m.metadata === "object") {
1587
- const md = m.metadata;
1588
- const ptr = md.asset_pointer ?? md.image_asset_pointer;
1589
- if (typeof ptr === "string") {
1590
- const existing = found.get(ptr);
1591
- found.set(
1592
- ptr,
1593
- existing?.messageId ? existing : { pointer: ptr, ...m?.id ? { messageId: m.id } : {} }
1594
- );
1595
- }
1596
- }
1597
- }
1598
- if (found.size > 0) finish();
1599
- };
1600
- });
1601
- }
1602
- const DEFAULT_ASYNC_IMAGE_TIMEOUT_MS = 18e4;
1603
- function configuredAsyncImageTimeoutMs() {
1604
- const raw = Number(process.env.OMNIROUTE_CGPT_WEB_IMAGE_TIMEOUT_MS);
1605
- if (!Number.isFinite(raw) || raw <= 0) return DEFAULT_ASYNC_IMAGE_TIMEOUT_MS;
1606
- return Math.floor(raw);
1607
- }
1608
- async function pollForAsyncImage(conversationId, ctx, opts = {}) {
1609
- const totalTimeoutMs = opts.timeoutMs ?? configuredAsyncImageTimeoutMs();
1610
- const deadline = Date.now() + totalTimeoutMs;
1611
- for (let attempt = 0; attempt < 2; attempt++) {
1612
- const remaining = deadline - Date.now();
1613
- if (remaining <= 0) break;
1614
- const wssUrl = await registerWebSocket(ctx);
1615
- if (!wssUrl) {
1616
- ctx.log?.warn?.(
1617
- "CGPT-WEB",
1618
- attempt === 0 ? "Could not register WebSocket \u2014 async image gen not retrievable" : `WebSocket re-registration failed on retry attempt ${attempt + 1}`
1619
- );
1620
- if (attempt === 0) continue;
1621
- return [];
1622
- }
1623
- ctx.log?.debug?.(
1624
- "CGPT-WEB",
1625
- `Registered WebSocket for async image (attempt ${attempt + 1}, ${remaining}ms remaining)`
1626
- );
1627
- const outcome = await waitForImageViaWebSocket(wssUrl, conversationId, remaining, ctx);
1628
- if (outcome.pointers.length > 0) return outcome.pointers;
1629
- if (ctx.signal?.aborted) return [];
1630
- if (!outcome.errored || outcome.gotAnyMessage) return [];
1631
- ctx.log?.warn?.(
1632
- "CGPT-WEB",
1633
- `WebSocket attempt ${attempt + 1} ended in transport error before any frame; retrying`
1634
- );
1635
- }
1636
- return [];
1637
- }
1638
- function makeImageResolver(ctx) {
1639
- const cache = /* @__PURE__ */ new Map();
1640
- return async (assetPointer, conversationId, parentMessageId) => {
1641
- if (cache.has(assetPointer)) return cache.get(assetPointer) ?? null;
1642
- let fileId = null;
1643
- if (assetPointer.startsWith(FILE_SERVICE_PREFIX)) {
1644
- fileId = assetPointer.slice(FILE_SERVICE_PREFIX.length);
1645
- } else if (assetPointer.startsWith(SEDIMENT_PREFIX)) {
1646
- fileId = assetPointer.slice(SEDIMENT_PREFIX.length);
1647
- } else {
1648
- ctx.log?.warn?.("CGPT-WEB", `Unknown asset_pointer scheme: ${assetPointer}`);
1649
- }
1650
- let signedUrl = null;
1651
- if (fileId) {
1652
- signedUrl = await fetchDownloadUrl(
1653
- `${CHATGPT_BASE}/backend-api/files/${encodeURIComponent(fileId)}/download`,
1654
- ctx
1655
- );
1656
- if (!signedUrl && conversationId) {
1657
- signedUrl = await fetchDownloadUrl(
1658
- `${CHATGPT_BASE}/backend-api/conversation/${encodeURIComponent(conversationId)}/attachment/${encodeURIComponent(fileId)}/download`,
1659
- ctx
1660
- );
1661
- }
1662
- }
1663
- let finalUrl = null;
1664
- if (signedUrl) {
1665
- finalUrl = await imageUrlToCachedImageUrl(
1666
- signedUrl,
1667
- ctx,
1668
- conversationId && parentMessageId ? { conversationId, parentMessageId } : void 0
1669
- );
1670
- }
1671
- cache.set(assetPointer, finalUrl);
1672
- if (finalUrl) {
1673
- const preview = finalUrl.startsWith("data:") ? `data:... (${finalUrl.length} chars)` : finalUrl.slice(0, 80) + "...";
1674
- ctx.log?.debug?.("CGPT-WEB", `Resolved ${assetPointer} \u2192 ${preview}`);
1675
- }
1676
- return finalUrl;
1677
- };
1678
- }
1679
- class ChatGptWebExecutor extends BaseExecutor {
1680
- constructor() {
1681
- super("chatgpt-web", { id: "chatgpt-web", baseUrl: CONV_URL });
1682
- }
1683
- async execute({
1684
- model,
1685
- body,
1686
- stream,
1687
- credentials,
1688
- signal,
1689
- log,
1690
- onCredentialsRefreshed,
1691
- clientHeaders
1692
- }) {
1693
- const messages = body?.messages;
1694
- if (!messages || !Array.isArray(messages) || messages.length === 0) {
1695
- return {
1696
- response: errorResponse(400, "Missing or empty messages array"),
1697
- url: CONV_URL,
1698
- headers: {},
1699
- transformedBody: body
1700
- };
1701
- }
1702
- const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages(
1703
- body || {},
1704
- messages
1705
- );
1706
- if (!credentials.apiKey) {
1707
- return {
1708
- response: errorResponse(
1709
- 401,
1710
- "ChatGPT auth failed \u2014 paste your __Secure-next-auth.session-token cookie value."
1711
- ),
1712
- url: CONV_URL,
1713
- headers: {},
1714
- transformedBody: body
1715
- };
1716
- }
1717
- const cookie = credentials.apiKey;
1718
- let tokenEntry;
1719
- try {
1720
- tokenEntry = await exchangeSession(cookie, signal);
1721
- } catch (err) {
1722
- if (err instanceof SessionAuthError) {
1723
- log?.warn?.("CGPT-WEB", err.message);
1724
- return {
1725
- response: errorResponse(
1726
- 401,
1727
- "ChatGPT auth failed \u2014 re-paste your __Secure-next-auth.session-token cookie from chatgpt.com.",
1728
- "HTTP_401"
1729
- ),
1730
- url: SESSION_URL,
1731
- headers: {},
1732
- transformedBody: body
1733
- };
1734
- }
1735
- log?.error?.(
1736
- "CGPT-WEB",
1737
- `Session exchange failed: ${err instanceof Error ? err.message : String(err)}`
1738
- );
1739
- return {
1740
- response: errorResponse(
1741
- 502,
1742
- `ChatGPT session exchange failed: ${err instanceof Error ? err.message : String(err)}`
1743
- ),
1744
- url: SESSION_URL,
1745
- headers: {},
1746
- transformedBody: body
1747
- };
1748
- }
1749
- if (tokenEntry.refreshedCookie && tokenEntry.refreshedCookie !== cookie) {
1750
- const updated = { ...credentials, apiKey: tokenEntry.refreshedCookie };
1751
- try {
1752
- await onCredentialsRefreshed?.(updated);
1753
- } catch (err) {
1754
- log?.warn?.(
1755
- "CGPT-WEB",
1756
- `Failed to persist refreshed cookie: ${err instanceof Error ? err.message : String(err)}`
1757
- );
1758
- }
1759
- }
1760
- let dplInfo;
1761
- try {
1762
- dplInfo = await fetchDpl(cookie, signal);
1763
- } catch (err) {
1764
- log?.warn?.(
1765
- "CGPT-WEB",
1766
- `DPL warmup failed (continuing with fallback): ${err instanceof Error ? err.message : String(err)}`
1767
- );
1768
- dplInfo = {
1769
- dpl: `dpl=${OAI_CLIENT_VERSION.replace(/^prod-/, "")}`,
1770
- scriptSrc: `${CHATGPT_BASE}/_next/static/chunks/webpack-${randomHex(16)}.js`
1771
- };
1772
- }
1773
- const sessionId = randomUUID();
1774
- const deviceId = deviceIdFor(cookie);
1775
- await runSessionWarmup(
1776
- tokenEntry.accessToken,
1777
- tokenEntry.accountId,
1778
- sessionId,
1779
- deviceId,
1780
- cookie,
1781
- signal,
1782
- log
1783
- );
1784
- const resolvedModel = resolveChatGptModel(model, body, credentials.providerSpecificData);
1785
- const modelSlug = resolvedModel.slug;
1786
- const requestedEffort = resolvedModel.effort;
1787
- if (requestedEffort && isThinkingCapableModel(model, modelSlug)) {
1788
- await setUserThinkingEffort(
1789
- modelSlug,
1790
- requestedEffort,
1791
- tokenEntry.accessToken,
1792
- tokenEntry.accountId,
1793
- sessionId,
1794
- deviceId,
1795
- cookie,
1796
- signal,
1797
- log
1798
- );
1799
- }
1800
- let reqs;
1801
- try {
1802
- reqs = await prepareChatRequirements(
1803
- tokenEntry.accessToken,
1804
- tokenEntry.accountId,
1805
- sessionId,
1806
- deviceId,
1807
- cookie,
1808
- dplInfo,
1809
- signal,
1810
- log
1811
- );
1812
- } catch (err) {
1813
- if (err instanceof SentinelBlockedError) {
1814
- log?.warn?.("CGPT-WEB", err.message);
1815
- return {
1816
- response: errorResponse(
1817
- 403,
1818
- "ChatGPT blocked the request (Sentinel/Turnstile required). Try again later or open chatgpt.com in a browser to refresh state.",
1819
- "SENTINEL_BLOCKED"
1820
- ),
1821
- url: SENTINEL_PREPARE_URL,
1822
- headers: {},
1823
- transformedBody: body
1824
- };
1825
- }
1826
- log?.error?.(
1827
- "CGPT-WEB",
1828
- `Sentinel failed: ${err instanceof Error ? err.message : String(err)}`
1829
- );
1830
- return {
1831
- response: errorResponse(
1832
- 502,
1833
- `ChatGPT sentinel failed: ${err instanceof Error ? err.message : String(err)}`
1834
- ),
1835
- url: SENTINEL_PREPARE_URL,
1836
- headers: {},
1837
- transformedBody: body
1838
- };
1839
- }
1840
- log?.debug?.(
1841
- "CGPT-WEB",
1842
- `sentinel: token=${reqs.token ? "y" : "n"} pow=${reqs.proofofwork?.required ? "y" : "n"} turnstile=${reqs.turnstile?.required ? "y" : "n"}`
1843
- );
1844
- const turnstileToken = typeof credentials.providerSpecificData?.turnstileToken === "string" ? credentials.providerSpecificData.turnstileToken : null;
1845
- let proofToken = null;
1846
- if (reqs.proofofwork?.required && reqs.proofofwork.seed && reqs.proofofwork.difficulty) {
1847
- const powConfig = buildPrekeyConfig(CHATGPT_USER_AGENT, dplInfo.dpl, dplInfo.scriptSrc);
1848
- proofToken = await solveProofOfWork(
1849
- reqs.proofofwork.seed,
1850
- reqs.proofofwork.difficulty,
1851
- powConfig,
1852
- log
1853
- );
1854
- }
1855
- const parsed = parseOpenAIMessages(effectiveMessages);
1856
- if (!parsed.currentMsg.trim() && parsed.history.length === 0) {
1857
- return {
1858
- response: errorResponse(400, "Empty user message"),
1859
- url: CONV_URL,
1860
- headers: {},
1861
- transformedBody: body
1862
- };
1863
- }
1864
- const imageEdit = looksLikeImageEditRequest(parsed);
1865
- const continuation = imageEdit ? parsed.latestImageContext : null;
1866
- const forImageGen = looksLikeImageGenRequest(parsed) || imageEdit;
1867
- const persistConversation = forImageGen || !!continuation;
1868
- if (forImageGen) {
1869
- log?.debug?.(
1870
- "CGPT-WEB",
1871
- continuation ? "Image edit intent detected \u2014 continuing saved image conversation" : "Image-gen intent detected \u2014 disabling Temporary Chat for this turn"
1872
- );
1873
- } else if (resolvedModel.isPro) {
1874
- log?.debug?.("CGPT-WEB", "GPT-5.5 Pro text request \u2014 keeping Temporary Chat enabled");
1875
- }
1876
- const parentMessageId = continuation?.parentMessageId ?? randomUUID();
1877
- const cgptBody = buildConversationBody(parsed, modelSlug, parentMessageId, {
1878
- persistConversation,
1879
- thinkingEffort: requestedEffort,
1880
- continuation
1881
- });
1882
- const headers = {
1883
- ...browserHeaders(),
1884
- ...oaiHeaders(sessionId, deviceId),
1885
- "Content-Type": "application/json",
1886
- Accept: "text/event-stream",
1887
- Authorization: `Bearer ${tokenEntry.accessToken}`,
1888
- Cookie: buildSessionCookieHeader(cookie)
1889
- };
1890
- if (tokenEntry.accountId) headers["chatgpt-account-id"] = tokenEntry.accountId;
1891
- if (reqs.token) headers["openai-sentinel-chat-requirements-token"] = reqs.token;
1892
- if (reqs.prepare_token)
1893
- headers["openai-sentinel-chat-requirements-prepare-token"] = reqs.prepare_token;
1894
- if (proofToken) headers["openai-sentinel-proof-token"] = proofToken;
1895
- if (turnstileToken) headers["openai-sentinel-turnstile-token"] = turnstileToken;
1896
- log?.info?.("CGPT-WEB", `Conversation request \u2192 ${modelSlug} (pow=${!!proofToken})`);
1897
- let response;
1898
- try {
1899
- response = await tlsFetchChatGpt(CONV_URL, {
1900
- method: "POST",
1901
- headers,
1902
- body: JSON.stringify(cgptBody),
1903
- timeoutMs: 12e4,
1904
- // generations can take a while
1905
- signal,
1906
- // For real-time streaming, ask the TLS client to write the body to
1907
- // a temp file and surface it as a ReadableStream as it arrives —
1908
- // otherwise long generations buffer entirely before the client sees
1909
- // anything (and the downstream HTTP request can time out).
1910
- stream
1911
- });
1912
- } catch (err) {
1913
- log?.error?.("CGPT-WEB", `Fetch failed: ${err instanceof Error ? err.message : String(err)}`);
1914
- const code = err instanceof TlsClientUnavailableError ? "TLS_UNAVAILABLE" : void 0;
1915
- return {
1916
- response: errorResponse(
1917
- 502,
1918
- `ChatGPT connection failed: ${err instanceof Error ? err.message : String(err)}`,
1919
- code
1920
- ),
1921
- url: CONV_URL,
1922
- headers,
1923
- transformedBody: cgptBody
1924
- };
1925
- }
1926
- if (response.status >= 400) {
1927
- const status = response.status;
1928
- log?.warn?.("CGPT-WEB", `conv ${status}: ${(response.text || "").slice(0, 400)}`);
1929
- const errMsg = describeChatGptWebHttpError(status);
1930
- if (status === 401 || status === 403) {
1931
- tokenCache.delete(cookieKey(cookie));
1932
- }
1933
- log?.warn?.("CGPT-WEB", errMsg);
1934
- return {
1935
- response: errorResponse(status, errMsg, `HTTP_${status}`),
1936
- url: CONV_URL,
1937
- headers,
1938
- transformedBody: cgptBody
1939
- };
1940
- }
1941
- let bodyStream;
1942
- if (response.body) {
1943
- bodyStream = response.body;
1944
- } else if (response.text) {
1945
- bodyStream = stringToStream(response.text);
1946
- } else {
1947
- return {
1948
- response: errorResponse(502, "ChatGPT returned empty response body"),
1949
- url: CONV_URL,
1950
- headers,
1951
- transformedBody: cgptBody
1952
- };
1953
- }
1954
- const cid = `chatcmpl-cgpt-${crypto.randomUUID().slice(0, 12)}`;
1955
- const created = Math.floor(Date.now() / 1e3);
1956
- const resolverCtx = {
1957
- accessToken: tokenEntry.accessToken,
1958
- accountId: tokenEntry.accountId,
1959
- sessionId,
1960
- deviceId,
1961
- cookie,
1962
- signal,
1963
- log,
1964
- publicBaseUrl: derivePublicBaseUrl(clientHeaders, log)
1965
- };
1966
- const imageResolver = makeImageResolver(resolverCtx);
1967
- const pollAsyncImage = (conversationId) => pollForAsyncImage(conversationId, resolverCtx);
1968
- const pollFinalAnswer = resolvedModel.isPro ? (conversationId) => pollForFinalAssistantAnswer(conversationId, resolverCtx) : null;
1969
- const toolMode = hasTools && !forImageGen;
1970
- let finalResponse;
1971
- if (stream && !toolMode) {
1972
- const sseStream = buildStreamingResponse(
1973
- bodyStream,
1974
- model,
1975
- cid,
1976
- created,
1977
- imageResolver,
1978
- pollAsyncImage,
1979
- pollFinalAnswer,
1980
- log,
1981
- signal
1982
- );
1983
- finalResponse = new Response(sseStream, {
1984
- status: 200,
1985
- headers: {
1986
- "Content-Type": "text/event-stream",
1987
- "Cache-Control": "no-cache",
1988
- "X-Accel-Buffering": "no"
1989
- }
1990
- });
1991
- } else {
1992
- finalResponse = await buildNonStreamingResponse(
1993
- bodyStream,
1994
- model,
1995
- cid,
1996
- created,
1997
- parsed.currentMsg,
1998
- imageResolver,
1999
- pollAsyncImage,
2000
- pollFinalAnswer,
2001
- log,
2002
- signal
2003
- );
2004
- if (toolMode) {
2005
- finalResponse = await buildToolModeResponse(finalResponse, requestedTools, stream, {
2006
- cid,
2007
- created,
2008
- model
2009
- });
2010
- }
2011
- }
2012
- return { response: finalResponse, url: CONV_URL, headers, transformedBody: cgptBody };
2013
- }
2014
- }
2015
- const ENTITY_RE = /entity\["[^"]*","([^"]*)"[^\]]*\]/g;
2016
- function cleanChatGptText(text) {
2017
- return text.replace(ENTITY_RE, "$1");
2018
- }
2019
- function stringToStream(text) {
2020
- const encoder = new TextEncoder();
2021
- return new ReadableStream({
2022
- start(controller) {
2023
- controller.enqueue(encoder.encode(text));
2024
- controller.close();
2025
- }
2026
- });
2027
- }
2028
- function __resetChatGptWebCachesForTesting() {
2029
- tokenCache.clear();
2030
- warmupCache.clear();
2031
- thinkingEffortCache.clear();
2032
- deviceIdCache.clear();
2033
- __resetChatGptImageCacheForTesting();
2034
- dplCache = null;
2035
- }
2036
- const __derivePublicBaseUrlForTesting = derivePublicBaseUrl;
2037
- export {
2038
- ChatGptWebExecutor,
2039
- __derivePublicBaseUrlForTesting,
2040
- __resetChatGptWebCachesForTesting,
2041
- detectImageResolutionFailure
2042
- };