@amir83nasr/10router 0.1.12 → 0.1.15

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 (707) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +6 -8
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/prerender-manifest.json +22 -50
  5. package/.next/routes-manifest.json +0 -12
  6. package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js +2 -2
  7. package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
  9. package/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/(dashboard)/dashboard/combos/page.js +1 -1
  11. package/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  12. package/.next/server/app/(dashboard)/dashboard/console-log/page.js +1 -1
  13. package/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/(dashboard)/dashboard/endpoint/page.js +1 -1
  15. package/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page.js +2 -2
  17. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page.js +1 -1
  19. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page_client-reference-manifest.js +1 -1
  20. package/.next/server/app/(dashboard)/dashboard/page.js +1 -1
  21. package/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  22. package/.next/server/app/(dashboard)/dashboard/profile/page.js +1 -1
  23. package/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  24. package/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js +2 -2
  25. package/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  26. package/.next/server/app/(dashboard)/dashboard/providers/new/page.js +1 -1
  27. package/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  28. package/.next/server/app/(dashboard)/dashboard/providers/page.js +1 -1
  29. package/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  30. package/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js +2 -2
  31. package/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  32. package/.next/server/app/(dashboard)/dashboard/pxpipe/page.js +1 -1
  33. package/.next/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
  34. package/.next/server/app/(dashboard)/dashboard/quota/page.js +1 -1
  35. package/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/(dashboard)/dashboard/token-saver/page.js +1 -1
  37. package/.next/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/(dashboard)/dashboard/usage/page.js +1 -1
  39. package/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  40. package/.next/server/app/_global-error/page.js +2 -2
  41. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/_global-error.html +1 -1
  43. package/.next/server/app/_global-error.rsc +1 -1
  44. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  45. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  46. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  47. package/.next/server/app/_not-found/page.js +1 -1
  48. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  49. package/.next/server/app/_not-found.html +1 -1
  50. package/.next/server/app/_not-found.rsc +6 -6
  51. package/.next/server/app/_not-found.segments/_full.segment.rsc +6 -6
  52. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +6 -6
  53. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/api/auth/login/route.js +1 -1
  55. package/.next/server/app/api/auth/logout/route.js +1 -1
  56. package/.next/server/app/api/auth/oidc/callback/route.js +1 -1
  57. package/.next/server/app/api/auth/oidc/start/route.js +1 -1
  58. package/.next/server/app/api/auth/oidc/test/route.js +1 -1
  59. package/.next/server/app/api/auth/reset-password/route.js +1 -1
  60. package/.next/server/app/api/auth/saml/acs/route.js +1 -1
  61. package/.next/server/app/api/auth/saml/metadata/route.js +2 -2
  62. package/.next/server/app/api/auth/saml/start/route.js +1 -1
  63. package/.next/server/app/api/auth/saml/test/route.js +1 -1
  64. package/.next/server/app/api/auth/status/route.js +1 -1
  65. package/.next/server/app/api/changelog/route.js +1 -1
  66. package/.next/server/app/api/cli-tools/all-statuses/route.js +1 -1
  67. package/.next/server/app/api/cli-tools/claude-settings/route.js +2 -2
  68. package/.next/server/app/api/cli-tools/codex-settings/route.js +1 -1
  69. package/.next/server/app/api/cli-tools/cowork-mcp-registry/route.js +1 -1
  70. package/.next/server/app/api/cli-tools/cowork-mcp-tools/route.js +1 -1
  71. package/.next/server/app/api/cli-tools/cowork-settings/route.js +1 -1
  72. package/.next/server/app/api/cli-tools/dsh-settings/route.js +1 -1
  73. package/.next/server/app/api/cli-tools/opencode-settings/route.js +1 -1
  74. package/.next/server/app/api/combos/[id]/route.js +1 -1
  75. package/.next/server/app/api/combos/route.js +1 -1
  76. package/.next/server/app/api/headroom/extras/route.js +1 -1
  77. package/.next/server/app/api/headroom/proxy/[...path]/route.js +1 -1
  78. package/.next/server/app/api/headroom/restart/route.js +1 -1
  79. package/.next/server/app/api/headroom/start/route.js +1 -1
  80. package/.next/server/app/api/headroom/status/route.js +1 -1
  81. package/.next/server/app/api/headroom/stop/route.js +1 -1
  82. package/.next/server/app/api/health/route.js +1 -1
  83. package/.next/server/app/api/init/route.js +1 -1
  84. package/.next/server/app/api/keys/[id]/route.js +1 -1
  85. package/.next/server/app/api/keys/route.js +1 -1
  86. package/.next/server/app/api/locale/route.js +1 -1
  87. package/.next/server/app/api/mcp/[plugin]/message/route.js +1 -1
  88. package/.next/server/app/api/mcp/[plugin]/sse/route.js +2 -2
  89. package/.next/server/app/api/media-providers/tts/deepgram/voices/route.js +1 -1
  90. package/.next/server/app/api/media-providers/tts/elevenlabs/voices/route.js +1 -1
  91. package/.next/server/app/api/media-providers/tts/inworld/voices/route.js +1 -1
  92. package/.next/server/app/api/media-providers/tts/minimax/voices/route.js +1 -1
  93. package/.next/server/app/api/media-providers/tts/voices/route.js +1 -1
  94. package/.next/server/app/api/models/alias/route.js +1 -1
  95. package/.next/server/app/api/models/availability/route.js +1 -1
  96. package/.next/server/app/api/models/catalog-sync/route.js +1 -1
  97. package/.next/server/app/api/models/custom/route.js +1 -1
  98. package/.next/server/app/api/models/disabled/route.js +1 -1
  99. package/.next/server/app/api/models/route.js +1 -1
  100. package/.next/server/app/api/models/test/route.js +1 -1
  101. package/.next/server/app/api/oauth/[provider]/[action]/route.js +1 -1
  102. package/.next/server/app/api/oauth/codex/bulk-import/route.js +1 -1
  103. package/.next/server/app/api/oauth/codex/import-token/route.js +1 -1
  104. package/.next/server/app/api/oauth/cursor/auto-import/route.js +2 -2
  105. package/.next/server/app/api/oauth/cursor/import/route.js +1 -1
  106. package/.next/server/app/api/oauth/gitlab/pat/route.js +1 -1
  107. package/.next/server/app/api/oauth/grok-cli/bulk-import/route.js +1 -1
  108. package/.next/server/app/api/oauth/iflow/cookie/route.js +1 -1
  109. package/.next/server/app/api/oauth/xiaomi-mimo/api-key/route.js +1 -1
  110. package/.next/server/app/api/oauth/xiaomi-mimo/auto-import/route.js +2 -2
  111. package/.next/server/app/api/pricing/route.js +1 -1
  112. package/.next/server/app/api/provider-nodes/[id]/route.js +1 -1
  113. package/.next/server/app/api/provider-nodes/route.js +1 -1
  114. package/.next/server/app/api/provider-nodes/validate/route.js +1 -1
  115. package/.next/server/app/api/providers/[id]/models/route.js +1 -1
  116. package/.next/server/app/api/providers/[id]/route.js +1 -1
  117. package/.next/server/app/api/providers/[id]/test/route.js +1 -1
  118. package/.next/server/app/api/providers/[id]/test-models/route.js +1 -1
  119. package/.next/server/app/api/providers/client/route.js +1 -1
  120. package/.next/server/app/api/providers/kilo/free-models/route.js +1 -1
  121. package/.next/server/app/api/providers/route.js +1 -1
  122. package/.next/server/app/api/providers/suggested-models/route.js +1 -1
  123. package/.next/server/app/api/providers/test-batch/route.js +1 -1
  124. package/.next/server/app/api/providers/validate/route.js +1 -1
  125. package/.next/server/app/api/proxy-pools/[id]/route.js +1 -1
  126. package/.next/server/app/api/proxy-pools/[id]/test/route.js +1 -1
  127. package/.next/server/app/api/proxy-pools/cloudflare-deploy/route.js +2 -2
  128. package/.next/server/app/api/proxy-pools/deno-deploy/route.js +2 -2
  129. package/.next/server/app/api/proxy-pools/route.js +1 -1
  130. package/.next/server/app/api/proxy-pools/vercel-deploy/route.js +2 -2
  131. package/.next/server/app/api/pxpipe/health/route.js +2 -2
  132. package/.next/server/app/api/pxpipe/install/route.js +1 -1
  133. package/.next/server/app/api/pxpipe/logs/route.js +1 -1
  134. package/.next/server/app/api/pxpipe/restart/route.js +1 -1
  135. package/.next/server/app/api/pxpipe/start/route.js +1 -1
  136. package/.next/server/app/api/pxpipe/stats/route.js +1 -1
  137. package/.next/server/app/api/pxpipe/status/route.js +1 -1
  138. package/.next/server/app/api/pxpipe/stop/route.js +1 -1
  139. package/.next/server/app/api/settings/database/route.js +1 -1
  140. package/.next/server/app/api/settings/proxy-test/route.js +1 -1
  141. package/.next/server/app/api/settings/require-login/route.js +1 -1
  142. package/.next/server/app/api/settings/route.js +1 -1
  143. package/.next/server/app/api/shutdown/route.js +1 -1
  144. package/.next/server/app/api/tags/route.js +1 -1
  145. package/.next/server/app/api/translator/console-logs/route.js +1 -1
  146. package/.next/server/app/api/translator/console-logs/stream/route.js +2 -2
  147. package/.next/server/app/api/translator/load/route.js +1 -1
  148. package/.next/server/app/api/translator/save/route.js +1 -1
  149. package/.next/server/app/api/translator/send/route.js +1 -1
  150. package/.next/server/app/api/translator/translate/route.js +1 -1
  151. package/.next/server/app/api/tunnel/disable/route.js +1 -1
  152. package/.next/server/app/api/tunnel/enable/route.js +1 -1
  153. package/.next/server/app/api/tunnel/status/route.js +1 -1
  154. package/.next/server/app/api/tunnel/tailscale-check/route.js +1 -1
  155. package/.next/server/app/api/tunnel/tailscale-disable/route.js +1 -1
  156. package/.next/server/app/api/tunnel/tailscale-enable/route.js +1 -1
  157. package/.next/server/app/api/tunnel/tailscale-install/route.js +3 -3
  158. package/.next/server/app/api/usage/[connectionId]/codex-reset-credits/route.js +1 -1
  159. package/.next/server/app/api/usage/[connectionId]/route.js +1 -1
  160. package/.next/server/app/api/usage/chart/route.js +1 -1
  161. package/.next/server/app/api/usage/health/route.js +1 -1
  162. package/.next/server/app/api/usage/history/route.js +1 -1
  163. package/.next/server/app/api/usage/logs/route.js +1 -1
  164. package/.next/server/app/api/usage/providers/route.js +1 -1
  165. package/.next/server/app/api/usage/request-details/route.js +1 -1
  166. package/.next/server/app/api/usage/request-logs/route.js +1 -1
  167. package/.next/server/app/api/usage/stats/route.js +1 -1
  168. package/.next/server/app/api/usage/stream/route.js +2 -2
  169. package/.next/server/app/api/v1/api/chat/route.js +1 -1
  170. package/.next/server/app/api/v1/audio/speech/route.js +1 -1
  171. package/.next/server/app/api/v1/audio/transcriptions/route.js +1 -1
  172. package/.next/server/app/api/v1/audio/voices/route.js +1 -1
  173. package/.next/server/app/api/v1/chat/completions/route.js +1 -1
  174. package/.next/server/app/api/v1/embeddings/route.js +1 -1
  175. package/.next/server/app/api/v1/images/generations/route.js +2 -2
  176. package/.next/server/app/api/v1/messages/count_tokens/route.js +1 -1
  177. package/.next/server/app/api/v1/messages/route.js +1 -1
  178. package/.next/server/app/api/v1/models/[...model]/route.js +1 -1
  179. package/.next/server/app/api/v1/models/info/route.js +1 -1
  180. package/.next/server/app/api/v1/models/route.js +1 -1
  181. package/.next/server/app/api/v1/responses/compact/route.js +1 -1
  182. package/.next/server/app/api/v1/responses/route.js +1 -1
  183. package/.next/server/app/api/v1/route.js +1 -1
  184. package/.next/server/app/api/v1/search/route.js +1 -1
  185. package/.next/server/app/api/v1/systemone/route.js +1 -1
  186. package/.next/server/app/api/v1/videos/[id]/route.js +1 -1
  187. package/.next/server/app/api/v1/videos/edits/route.js +1 -1
  188. package/.next/server/app/api/v1/videos/extensions/route.js +1 -1
  189. package/.next/server/app/api/v1/videos/generations/route.js +1 -1
  190. package/.next/server/app/api/v1/web/fetch/route.js +1 -1
  191. package/.next/server/app/api/v1beta/models/[...path]/route.js +1 -1
  192. package/.next/server/app/api/v1beta/models/route.js +1 -1
  193. package/.next/server/app/api/version/route.js +1 -1
  194. package/.next/server/app/api/version/shutdown/route.js +1 -1
  195. package/.next/server/app/api/version/update/route.js +1 -1
  196. package/.next/server/app/callback/page.js +1 -1
  197. package/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  198. package/.next/server/app/callback.html +1 -1
  199. package/.next/server/app/callback.rsc +7 -7
  200. package/.next/server/app/callback.segments/_full.segment.rsc +7 -7
  201. package/.next/server/app/callback.segments/_tree.segment.rsc +2 -2
  202. package/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +7 -7
  203. package/.next/server/app/dashboard/cli-tools.html +1 -1
  204. package/.next/server/app/dashboard/cli-tools.rsc +9 -9
  205. package/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +8 -8
  206. package/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +9 -9
  207. package/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +2 -2
  208. package/.next/server/app/dashboard/combos.html +1 -1
  209. package/.next/server/app/dashboard/combos.rsc +8 -8
  210. package/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +8 -8
  211. package/.next/server/app/dashboard/combos.segments/_full.segment.rsc +8 -8
  212. package/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +2 -2
  213. package/.next/server/app/dashboard/endpoint.html +1 -1
  214. package/.next/server/app/dashboard/endpoint.rsc +9 -9
  215. package/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +8 -8
  216. package/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +9 -9
  217. package/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +2 -2
  218. package/.next/server/app/dashboard/media-providers/systemone.html +1 -1
  219. package/.next/server/app/dashboard/media-providers/systemone.rsc +8 -8
  220. package/.next/server/app/dashboard/media-providers/systemone.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/systemone/__PAGE__.segment.rsc +8 -8
  221. package/.next/server/app/dashboard/media-providers/systemone.segments/_full.segment.rsc +8 -8
  222. package/.next/server/app/dashboard/media-providers/systemone.segments/_tree.segment.rsc +2 -2
  223. package/.next/server/app/dashboard/profile.html +1 -1
  224. package/.next/server/app/dashboard/profile.rsc +8 -8
  225. package/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +8 -8
  226. package/.next/server/app/dashboard/profile.segments/_full.segment.rsc +8 -8
  227. package/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +2 -2
  228. package/.next/server/app/dashboard/providers/new.html +1 -1
  229. package/.next/server/app/dashboard/providers/new.rsc +8 -8
  230. package/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +8 -8
  231. package/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +8 -8
  232. package/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +2 -2
  233. package/.next/server/app/dashboard/providers.html +1 -1
  234. package/.next/server/app/dashboard/providers.rsc +8 -8
  235. package/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +8 -8
  236. package/.next/server/app/dashboard/providers.segments/_full.segment.rsc +8 -8
  237. package/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +2 -2
  238. package/.next/server/app/dashboard/proxy-pools.html +1 -1
  239. package/.next/server/app/dashboard/proxy-pools.rsc +8 -8
  240. package/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +8 -8
  241. package/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +8 -8
  242. package/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +2 -2
  243. package/.next/server/app/dashboard/pxpipe.html +1 -1
  244. package/.next/server/app/dashboard/pxpipe.rsc +7 -7
  245. package/.next/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +7 -7
  246. package/.next/server/app/dashboard/pxpipe.segments/_full.segment.rsc +7 -7
  247. package/.next/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +2 -2
  248. package/.next/server/app/dashboard/quota.html +2 -2
  249. package/.next/server/app/dashboard/quota.rsc +9 -9
  250. package/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +9 -9
  251. package/.next/server/app/dashboard/quota.segments/_full.segment.rsc +9 -9
  252. package/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +2 -2
  253. package/.next/server/app/dashboard/settings/pricing/page.js +1 -1
  254. package/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  255. package/.next/server/app/dashboard/settings/pricing.html +1 -1
  256. package/.next/server/app/dashboard/settings/pricing.rsc +7 -7
  257. package/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +7 -7
  258. package/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +2 -2
  259. package/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +7 -7
  260. package/.next/server/app/dashboard/token-saver.html +1 -1
  261. package/.next/server/app/dashboard/token-saver.rsc +8 -8
  262. package/.next/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +8 -8
  263. package/.next/server/app/dashboard/token-saver.segments/_full.segment.rsc +8 -8
  264. package/.next/server/app/dashboard/token-saver.segments/_tree.segment.rsc +2 -2
  265. package/.next/server/app/dashboard/usage.html +2 -2
  266. package/.next/server/app/dashboard/usage.rsc +8 -8
  267. package/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +8 -8
  268. package/.next/server/app/dashboard/usage.segments/_full.segment.rsc +8 -8
  269. package/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +2 -2
  270. package/.next/server/app/dashboard.html +1 -1
  271. package/.next/server/app/dashboard.rsc +9 -9
  272. package/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +8 -8
  273. package/.next/server/app/dashboard.segments/_full.segment.rsc +9 -9
  274. package/.next/server/app/dashboard.segments/_tree.segment.rsc +2 -2
  275. package/.next/server/app/index.html +1 -1
  276. package/.next/server/app/index.rsc +6 -6
  277. package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -6
  278. package/.next/server/app/index.segments/_full.segment.rsc +6 -6
  279. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  280. package/.next/server/app/landing/page.js +1 -1
  281. package/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  282. package/.next/server/app/landing.html +1 -1
  283. package/.next/server/app/landing.rsc +7 -7
  284. package/.next/server/app/landing.segments/_full.segment.rsc +7 -7
  285. package/.next/server/app/landing.segments/_tree.segment.rsc +2 -2
  286. package/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +7 -7
  287. package/.next/server/app/login/page.js +1 -1
  288. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  289. package/.next/server/app/login.html +1 -1
  290. package/.next/server/app/login.rsc +6 -6
  291. package/.next/server/app/login.segments/_full.segment.rsc +6 -6
  292. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  293. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +6 -6
  294. package/.next/server/app/manifest.webmanifest/route.js +1 -1
  295. package/.next/server/app/page.js +1 -1
  296. package/.next/server/app/page_client-reference-manifest.js +1 -1
  297. package/.next/server/app-paths-manifest.json +6 -8
  298. package/.next/server/chunks/1011.js +1 -1
  299. package/.next/server/chunks/1194.js +1 -1
  300. package/.next/server/chunks/1289.js +1 -1
  301. package/.next/server/chunks/1633.js +1 -1
  302. package/.next/server/chunks/1985.js +1 -1
  303. package/.next/server/chunks/2282.js +7 -7
  304. package/.next/server/chunks/2339.js +1 -1
  305. package/.next/server/chunks/2706.js +1 -1
  306. package/.next/server/chunks/2801.js +1 -1
  307. package/.next/server/chunks/3034.js +1 -1
  308. package/.next/server/chunks/3425.js +1 -1
  309. package/.next/server/chunks/6056.js +1 -1
  310. package/.next/server/chunks/6343.js +6 -6
  311. package/.next/server/chunks/7348.js +1 -1
  312. package/.next/server/chunks/9429.js +1 -1
  313. package/.next/server/middleware-build-manifest.js +1 -1
  314. package/.next/server/middleware.js +3 -3
  315. package/.next/server/pages/404.html +1 -1
  316. package/.next/server/pages/500.html +1 -1
  317. package/.next/server/prefetch-hints.json +0 -24
  318. package/.next/server/server-reference-manifest.js +1 -1
  319. package/.next/server/server-reference-manifest.json +1 -1
  320. package/.next/static/8QVpvFFKxoB53L449Kgan/_buildManifest.js +1 -0
  321. package/.next/static/chunks/1278-5800a984ad8ad005.js +1 -0
  322. package/.next/static/chunks/1660-7f2e79bde5eff607.js +1 -0
  323. package/.next/static/chunks/1699-13ee6864a8a31a96.js +67 -0
  324. package/.next/static/chunks/{2836-4781ea7374870f4a.js → 2836-d97f0aa2718945d5.js} +1 -1
  325. package/.next/static/chunks/{3577-1f02993330d7fba7.js → 3577-cd98d40e3099e1b0.js} +1 -1
  326. package/.next/static/chunks/5148-7d67073becfaf162.js +1 -0
  327. package/.next/static/chunks/{5862-6f3a3a6d4c00100d.js → 5862-f98c2f3d480b80d2.js} +1 -1
  328. package/.next/static/chunks/6428-5a5f71440049a4e6.js +1 -0
  329. package/.next/static/chunks/7128-78b41798c1177008.js +1 -0
  330. package/.next/static/chunks/7835-06b436358f3395f6.js +1 -0
  331. package/.next/static/chunks/9150-8316559e1687b4a8.js +1 -0
  332. package/.next/static/chunks/{9369-07e432041bb48a39.js → 9369-0d43b295968c2168.js} +1 -1
  333. package/.next/static/chunks/{9ce8c186-6cd204e9c27ecee1.js → 9ce8c186-3c7d7dbc5d428052.js} +1 -1
  334. package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/[toolId]/{page-36ad70a4f906c64b.js → page-dd70f2cee9c910a9.js} +3 -3
  335. package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/{page-aae6be7f75fcd819.js → page-3bab0c661f222ea3.js} +1 -1
  336. package/.next/static/chunks/app/(dashboard)/dashboard/combos/{page-18212c87b17b33cf.js → page-76cc2c386af12738.js} +1 -1
  337. package/.next/static/chunks/app/(dashboard)/dashboard/console-log/page-58a29f3cb409597a.js +1 -0
  338. package/.next/static/chunks/app/(dashboard)/dashboard/endpoint/page-d5f693c646ae044b.js +1 -0
  339. package/.next/static/chunks/app/(dashboard)/dashboard/media-providers/systemone/[id]/{page-610d962dd8bd1744.js → page-7340dad2b87640cf.js} +1 -1
  340. package/.next/static/chunks/app/(dashboard)/dashboard/media-providers/systemone/{page-9dbf4cd6901b6042.js → page-32e3e07a8f54ec11.js} +1 -1
  341. package/.next/static/chunks/app/(dashboard)/dashboard/page-a7f59da8c0db5cf1.js +1 -0
  342. package/.next/static/chunks/app/(dashboard)/dashboard/profile/{page-2ab30b6e1baf1efd.js → page-7123127fd841cfa5.js} +1 -1
  343. package/.next/static/chunks/app/(dashboard)/dashboard/providers/[id]/{page-b17607bc2ed06d50.js → page-fab6f4b4cccc1a6f.js} +1 -1
  344. package/.next/static/chunks/app/(dashboard)/dashboard/providers/new/{page-0e649a78a041306a.js → page-819e98f53bf2f4f7.js} +1 -1
  345. package/.next/static/chunks/app/(dashboard)/dashboard/providers/{page-b10c05192c664e8d.js → page-9054f870a5e0f5c6.js} +1 -1
  346. package/.next/static/chunks/app/(dashboard)/dashboard/proxy-pools/{page-b33051a3fc600082.js → page-3e4657b108582404.js} +2 -2
  347. package/.next/static/chunks/app/(dashboard)/dashboard/quota/{page-ee2a0fa91d9bea9c.js → page-61780f0a2b494680.js} +1 -1
  348. package/.next/static/chunks/app/(dashboard)/dashboard/token-saver/{page-bcc37fc2b4089f2f.js → page-4e366abb76514be7.js} +1 -1
  349. package/.next/static/chunks/app/(dashboard)/dashboard/usage/{page-2457f236bc58e590.js → page-2d71fa2936b16f45.js} +1 -1
  350. package/.next/static/chunks/app/(dashboard)/{layout-7ef1d599b3c4c6d2.js → layout-91f41c68685ed739.js} +1 -1
  351. package/.next/static/chunks/app/_global-error/page-9a2a13ac6b89ba91.js +1 -0
  352. package/.next/static/chunks/app/api/auth/login/route-9a2a13ac6b89ba91.js +1 -0
  353. package/.next/static/chunks/app/api/auth/logout/route-9a2a13ac6b89ba91.js +1 -0
  354. package/.next/static/chunks/app/api/auth/oidc/callback/route-9a2a13ac6b89ba91.js +1 -0
  355. package/.next/static/chunks/app/api/auth/oidc/start/route-9a2a13ac6b89ba91.js +1 -0
  356. package/.next/static/chunks/app/api/auth/oidc/test/route-9a2a13ac6b89ba91.js +1 -0
  357. package/.next/static/chunks/app/api/auth/reset-password/route-9a2a13ac6b89ba91.js +1 -0
  358. package/.next/static/chunks/app/api/auth/saml/acs/route-9a2a13ac6b89ba91.js +1 -0
  359. package/.next/static/chunks/app/api/auth/saml/metadata/route-9a2a13ac6b89ba91.js +1 -0
  360. package/.next/static/chunks/app/api/auth/saml/start/route-9a2a13ac6b89ba91.js +1 -0
  361. package/.next/static/chunks/app/api/auth/saml/test/route-9a2a13ac6b89ba91.js +1 -0
  362. package/.next/static/chunks/app/api/auth/status/route-9a2a13ac6b89ba91.js +1 -0
  363. package/.next/static/chunks/app/api/changelog/route-9a2a13ac6b89ba91.js +1 -0
  364. package/.next/static/chunks/app/api/cli-tools/all-statuses/route-9a2a13ac6b89ba91.js +1 -0
  365. package/.next/static/chunks/app/api/cli-tools/claude-settings/route-9a2a13ac6b89ba91.js +1 -0
  366. package/.next/static/chunks/app/api/cli-tools/codex-settings/route-9a2a13ac6b89ba91.js +1 -0
  367. package/.next/static/chunks/app/api/cli-tools/cowork-mcp-registry/route-9a2a13ac6b89ba91.js +1 -0
  368. package/.next/static/chunks/app/api/cli-tools/cowork-mcp-tools/route-9a2a13ac6b89ba91.js +1 -0
  369. package/.next/static/chunks/app/api/cli-tools/cowork-settings/route-9a2a13ac6b89ba91.js +1 -0
  370. package/.next/static/chunks/app/api/cli-tools/dsh-settings/route-9a2a13ac6b89ba91.js +1 -0
  371. package/.next/static/chunks/app/api/cli-tools/opencode-settings/route-9a2a13ac6b89ba91.js +1 -0
  372. package/.next/static/chunks/app/api/combos/[id]/route-9a2a13ac6b89ba91.js +1 -0
  373. package/.next/static/chunks/app/api/combos/route-9a2a13ac6b89ba91.js +1 -0
  374. package/.next/static/chunks/app/api/headroom/extras/route-9a2a13ac6b89ba91.js +1 -0
  375. package/.next/static/chunks/app/api/headroom/proxy/[...path]/route-9a2a13ac6b89ba91.js +1 -0
  376. package/.next/static/chunks/app/api/headroom/restart/route-9a2a13ac6b89ba91.js +1 -0
  377. package/.next/static/chunks/app/api/headroom/start/route-9a2a13ac6b89ba91.js +1 -0
  378. package/.next/static/chunks/app/api/headroom/status/route-9a2a13ac6b89ba91.js +1 -0
  379. package/.next/static/chunks/app/api/headroom/stop/route-9a2a13ac6b89ba91.js +1 -0
  380. package/.next/static/chunks/app/api/health/route-9a2a13ac6b89ba91.js +1 -0
  381. package/.next/static/chunks/app/api/init/route-9a2a13ac6b89ba91.js +1 -0
  382. package/.next/static/chunks/app/api/keys/[id]/route-9a2a13ac6b89ba91.js +1 -0
  383. package/.next/static/chunks/app/api/keys/route-9a2a13ac6b89ba91.js +1 -0
  384. package/.next/static/chunks/app/api/locale/route-9a2a13ac6b89ba91.js +1 -0
  385. package/.next/static/chunks/app/api/mcp/[plugin]/message/route-9a2a13ac6b89ba91.js +1 -0
  386. package/.next/static/chunks/app/api/mcp/[plugin]/sse/route-9a2a13ac6b89ba91.js +1 -0
  387. package/.next/static/chunks/app/api/media-providers/tts/deepgram/voices/route-9a2a13ac6b89ba91.js +1 -0
  388. package/.next/static/chunks/app/api/media-providers/tts/elevenlabs/voices/route-9a2a13ac6b89ba91.js +1 -0
  389. package/.next/static/chunks/app/api/media-providers/tts/inworld/voices/route-9a2a13ac6b89ba91.js +1 -0
  390. package/.next/static/chunks/app/api/media-providers/tts/minimax/voices/route-9a2a13ac6b89ba91.js +1 -0
  391. package/.next/static/chunks/app/api/media-providers/tts/voices/route-9a2a13ac6b89ba91.js +1 -0
  392. package/.next/static/chunks/app/api/models/alias/route-9a2a13ac6b89ba91.js +1 -0
  393. package/.next/static/chunks/app/api/models/availability/route-9a2a13ac6b89ba91.js +1 -0
  394. package/.next/static/chunks/app/api/models/catalog-sync/route-9a2a13ac6b89ba91.js +1 -0
  395. package/.next/static/chunks/app/api/models/custom/route-9a2a13ac6b89ba91.js +1 -0
  396. package/.next/static/chunks/app/api/models/disabled/route-9a2a13ac6b89ba91.js +1 -0
  397. package/.next/static/chunks/app/api/models/route-9a2a13ac6b89ba91.js +1 -0
  398. package/.next/static/chunks/app/api/models/test/route-9a2a13ac6b89ba91.js +1 -0
  399. package/.next/static/chunks/app/api/oauth/[provider]/[action]/route-9a2a13ac6b89ba91.js +1 -0
  400. package/.next/static/chunks/app/api/oauth/codex/bulk-import/route-9a2a13ac6b89ba91.js +1 -0
  401. package/.next/static/chunks/app/api/oauth/codex/import-token/route-9a2a13ac6b89ba91.js +1 -0
  402. package/.next/static/chunks/app/api/oauth/cursor/auto-import/route-9a2a13ac6b89ba91.js +1 -0
  403. package/.next/static/chunks/app/api/oauth/cursor/import/route-9a2a13ac6b89ba91.js +1 -0
  404. package/.next/static/chunks/app/api/oauth/gitlab/pat/route-9a2a13ac6b89ba91.js +1 -0
  405. package/.next/static/chunks/app/api/oauth/grok-cli/bulk-import/route-9a2a13ac6b89ba91.js +1 -0
  406. package/.next/static/chunks/app/api/oauth/iflow/cookie/route-9a2a13ac6b89ba91.js +1 -0
  407. package/.next/static/chunks/app/api/oauth/xiaomi-mimo/api-key/route-9a2a13ac6b89ba91.js +1 -0
  408. package/.next/static/chunks/app/api/oauth/xiaomi-mimo/auto-import/route-9a2a13ac6b89ba91.js +1 -0
  409. package/.next/static/chunks/app/api/pricing/route-9a2a13ac6b89ba91.js +1 -0
  410. package/.next/static/chunks/app/api/provider-nodes/[id]/route-9a2a13ac6b89ba91.js +1 -0
  411. package/.next/static/chunks/app/api/provider-nodes/route-9a2a13ac6b89ba91.js +1 -0
  412. package/.next/static/chunks/app/api/provider-nodes/validate/route-9a2a13ac6b89ba91.js +1 -0
  413. package/.next/static/chunks/app/api/providers/[id]/models/route-9a2a13ac6b89ba91.js +1 -0
  414. package/.next/static/chunks/app/api/providers/[id]/route-9a2a13ac6b89ba91.js +1 -0
  415. package/.next/static/chunks/app/api/providers/[id]/test/route-9a2a13ac6b89ba91.js +1 -0
  416. package/.next/static/chunks/app/api/providers/[id]/test-models/route-9a2a13ac6b89ba91.js +1 -0
  417. package/.next/static/chunks/app/api/providers/client/route-9a2a13ac6b89ba91.js +1 -0
  418. package/.next/static/chunks/app/api/providers/kilo/free-models/route-9a2a13ac6b89ba91.js +1 -0
  419. package/.next/static/chunks/app/api/providers/route-9a2a13ac6b89ba91.js +1 -0
  420. package/.next/static/chunks/app/api/providers/suggested-models/route-9a2a13ac6b89ba91.js +1 -0
  421. package/.next/static/chunks/app/api/providers/test-batch/route-9a2a13ac6b89ba91.js +1 -0
  422. package/.next/static/chunks/app/api/providers/validate/route-9a2a13ac6b89ba91.js +1 -0
  423. package/.next/static/chunks/app/api/proxy-pools/[id]/route-9a2a13ac6b89ba91.js +1 -0
  424. package/.next/static/chunks/app/api/proxy-pools/[id]/test/route-9a2a13ac6b89ba91.js +1 -0
  425. package/.next/static/chunks/app/api/proxy-pools/cloudflare-deploy/route-9a2a13ac6b89ba91.js +1 -0
  426. package/.next/static/chunks/app/api/proxy-pools/deno-deploy/route-9a2a13ac6b89ba91.js +1 -0
  427. package/.next/static/chunks/app/api/proxy-pools/route-9a2a13ac6b89ba91.js +1 -0
  428. package/.next/static/chunks/app/api/proxy-pools/vercel-deploy/route-9a2a13ac6b89ba91.js +1 -0
  429. package/.next/static/chunks/app/api/pxpipe/health/route-9a2a13ac6b89ba91.js +1 -0
  430. package/.next/static/chunks/app/api/pxpipe/install/route-9a2a13ac6b89ba91.js +1 -0
  431. package/.next/static/chunks/app/api/pxpipe/logs/route-9a2a13ac6b89ba91.js +1 -0
  432. package/.next/static/chunks/app/api/pxpipe/restart/route-9a2a13ac6b89ba91.js +1 -0
  433. package/.next/static/chunks/app/api/pxpipe/start/route-9a2a13ac6b89ba91.js +1 -0
  434. package/.next/static/chunks/app/api/pxpipe/stats/route-9a2a13ac6b89ba91.js +1 -0
  435. package/.next/static/chunks/app/api/pxpipe/status/route-9a2a13ac6b89ba91.js +1 -0
  436. package/.next/static/chunks/app/api/pxpipe/stop/route-9a2a13ac6b89ba91.js +1 -0
  437. package/.next/static/chunks/app/api/settings/database/route-9a2a13ac6b89ba91.js +1 -0
  438. package/.next/static/chunks/app/api/settings/proxy-test/route-9a2a13ac6b89ba91.js +1 -0
  439. package/.next/static/chunks/app/api/settings/require-login/route-9a2a13ac6b89ba91.js +1 -0
  440. package/.next/static/chunks/app/api/settings/route-9a2a13ac6b89ba91.js +1 -0
  441. package/.next/static/chunks/app/api/shutdown/route-9a2a13ac6b89ba91.js +1 -0
  442. package/.next/static/chunks/app/api/tags/route-9a2a13ac6b89ba91.js +1 -0
  443. package/.next/static/chunks/app/api/translator/console-logs/route-9a2a13ac6b89ba91.js +1 -0
  444. package/.next/static/chunks/app/api/translator/console-logs/stream/route-9a2a13ac6b89ba91.js +1 -0
  445. package/.next/static/chunks/app/api/translator/load/route-9a2a13ac6b89ba91.js +1 -0
  446. package/.next/static/chunks/app/api/translator/save/route-9a2a13ac6b89ba91.js +1 -0
  447. package/.next/static/chunks/app/api/translator/send/route-9a2a13ac6b89ba91.js +1 -0
  448. package/.next/static/chunks/app/api/translator/translate/route-9a2a13ac6b89ba91.js +1 -0
  449. package/.next/static/chunks/app/api/tunnel/disable/route-9a2a13ac6b89ba91.js +1 -0
  450. package/.next/static/chunks/app/api/tunnel/enable/route-9a2a13ac6b89ba91.js +1 -0
  451. package/.next/static/chunks/app/api/tunnel/status/route-9a2a13ac6b89ba91.js +1 -0
  452. package/.next/static/chunks/app/api/tunnel/tailscale-check/route-9a2a13ac6b89ba91.js +1 -0
  453. package/.next/static/chunks/app/api/tunnel/tailscale-disable/route-9a2a13ac6b89ba91.js +1 -0
  454. package/.next/static/chunks/app/api/tunnel/tailscale-enable/route-9a2a13ac6b89ba91.js +1 -0
  455. package/.next/static/chunks/app/api/tunnel/tailscale-install/route-9a2a13ac6b89ba91.js +1 -0
  456. package/.next/static/chunks/app/api/usage/[connectionId]/codex-reset-credits/route-9a2a13ac6b89ba91.js +1 -0
  457. package/.next/static/chunks/app/api/usage/[connectionId]/route-9a2a13ac6b89ba91.js +1 -0
  458. package/.next/static/chunks/app/api/usage/chart/route-9a2a13ac6b89ba91.js +1 -0
  459. package/.next/static/chunks/app/api/usage/health/route-9a2a13ac6b89ba91.js +1 -0
  460. package/.next/static/chunks/app/api/usage/history/route-9a2a13ac6b89ba91.js +1 -0
  461. package/.next/static/chunks/app/api/usage/logs/route-9a2a13ac6b89ba91.js +1 -0
  462. package/.next/static/chunks/app/api/usage/providers/route-9a2a13ac6b89ba91.js +1 -0
  463. package/.next/static/chunks/app/api/usage/request-details/route-9a2a13ac6b89ba91.js +1 -0
  464. package/.next/static/chunks/app/api/usage/request-logs/route-9a2a13ac6b89ba91.js +1 -0
  465. package/.next/static/chunks/app/api/usage/stats/route-9a2a13ac6b89ba91.js +1 -0
  466. package/.next/static/chunks/app/api/usage/stream/route-9a2a13ac6b89ba91.js +1 -0
  467. package/.next/static/chunks/app/api/v1/api/chat/route-9a2a13ac6b89ba91.js +1 -0
  468. package/.next/static/chunks/app/api/v1/audio/speech/route-9a2a13ac6b89ba91.js +1 -0
  469. package/.next/static/chunks/app/api/v1/audio/transcriptions/route-9a2a13ac6b89ba91.js +1 -0
  470. package/.next/static/chunks/app/api/v1/audio/voices/route-9a2a13ac6b89ba91.js +1 -0
  471. package/.next/static/chunks/app/api/v1/chat/completions/route-9a2a13ac6b89ba91.js +1 -0
  472. package/.next/static/chunks/app/api/v1/embeddings/route-9a2a13ac6b89ba91.js +1 -0
  473. package/.next/static/chunks/app/api/v1/images/generations/route-9a2a13ac6b89ba91.js +1 -0
  474. package/.next/static/chunks/app/api/v1/messages/count_tokens/route-9a2a13ac6b89ba91.js +1 -0
  475. package/.next/static/chunks/app/api/v1/messages/route-9a2a13ac6b89ba91.js +1 -0
  476. package/.next/static/chunks/app/api/v1/models/[...model]/route-9a2a13ac6b89ba91.js +1 -0
  477. package/.next/static/chunks/app/api/v1/models/info/route-9a2a13ac6b89ba91.js +1 -0
  478. package/.next/static/chunks/app/api/v1/models/route-9a2a13ac6b89ba91.js +1 -0
  479. package/.next/static/chunks/app/api/v1/responses/compact/route-9a2a13ac6b89ba91.js +1 -0
  480. package/.next/static/chunks/app/api/v1/responses/route-9a2a13ac6b89ba91.js +1 -0
  481. package/.next/static/chunks/app/api/v1/route-9a2a13ac6b89ba91.js +1 -0
  482. package/.next/static/chunks/app/api/v1/search/route-9a2a13ac6b89ba91.js +1 -0
  483. package/.next/static/chunks/app/api/v1/systemone/route-9a2a13ac6b89ba91.js +1 -0
  484. package/.next/static/chunks/app/api/v1/videos/[id]/route-9a2a13ac6b89ba91.js +1 -0
  485. package/.next/static/chunks/app/api/v1/videos/edits/route-9a2a13ac6b89ba91.js +1 -0
  486. package/.next/static/chunks/app/api/v1/videos/extensions/route-9a2a13ac6b89ba91.js +1 -0
  487. package/.next/static/chunks/app/api/v1/videos/generations/route-9a2a13ac6b89ba91.js +1 -0
  488. package/.next/static/chunks/app/api/v1/web/fetch/route-9a2a13ac6b89ba91.js +1 -0
  489. package/.next/static/chunks/app/api/v1beta/models/[...path]/route-9a2a13ac6b89ba91.js +1 -0
  490. package/.next/static/chunks/app/api/v1beta/models/route-9a2a13ac6b89ba91.js +1 -0
  491. package/.next/static/chunks/app/api/version/route-9a2a13ac6b89ba91.js +1 -0
  492. package/.next/static/chunks/app/api/version/shutdown/route-9a2a13ac6b89ba91.js +1 -0
  493. package/.next/static/chunks/app/api/version/update/route-9a2a13ac6b89ba91.js +1 -0
  494. package/.next/static/chunks/app/callback/page-8b6862b2e58a129e.js +1 -0
  495. package/.next/static/chunks/app/dashboard/settings/pricing/page-c1dfa7608ff710d1.js +1 -0
  496. package/.next/static/chunks/app/landing/page-a76ba2642bd02bf5.js +1 -0
  497. package/.next/static/chunks/app/layout-cc98f6c7473b86a3.js +1 -0
  498. package/.next/static/chunks/app/manifest.webmanifest/route-9a2a13ac6b89ba91.js +1 -0
  499. package/.next/static/chunks/app/page-9a2a13ac6b89ba91.js +1 -0
  500. package/.next/static/chunks/next/dist/client/components/builtin/app-error-9a2a13ac6b89ba91.js +1 -0
  501. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-9a2a13ac6b89ba91.js +1 -0
  502. package/.next/static/chunks/next/dist/client/components/builtin/not-found-9a2a13ac6b89ba91.js +1 -0
  503. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9a2a13ac6b89ba91.js +1 -0
  504. package/.next/static/css/efaf98e3b295f727.css +1 -0
  505. package/CHANGELOG.md +22 -0
  506. package/open-sse/handlers/chatCore/claudeMessageBody.js +357 -0
  507. package/open-sse/handlers/chatCore/nonStreamingHandler.js +36 -110
  508. package/open-sse/handlers/chatCore/sseToJsonHandler.js +147 -4
  509. package/open-sse/handlers/chatCore.js +48 -12
  510. package/open-sse/translator/concerns/classifier.js +70 -0
  511. package/open-sse/translator/concerns/thinkingUnified.js +18 -6
  512. package/open-sse/translator/request/claude-to-openai.js +20 -0
  513. package/open-sse/translator/request/openai-to-claude.js +11 -0
  514. package/package.json +1 -2
  515. package/src/app/(dashboard)/dashboard/cli-tools/components/cards/ClaudeToolCard.tsx +22 -0
  516. package/src/app/api/cli-tools/claude-settings/route.js +20 -0
  517. package/src/app/globals.css +16 -37
  518. package/src/components/app-sidebar.tsx +0 -1
  519. package/src/shared/components/Header.tsx +0 -8
  520. package/src/shared/components/layouts/DashboardLayout.tsx +2 -8
  521. package/src/shared/constants/cliTools.js +13 -0
  522. package/.next/server/app/(dashboard)/dashboard/basic-chat/page.js +0 -1
  523. package/.next/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +0 -1
  524. package/.next/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +0 -1
  525. package/.next/server/app/api/dashboard/chat/completions/route.js +0 -1
  526. package/.next/server/app/api/dashboard/chat/completions/route.js.nft.json +0 -1
  527. package/.next/server/app/api/dashboard/chat/completions/route_client-reference-manifest.js +0 -1
  528. package/.next/server/app/dashboard/basic-chat.html +0 -1
  529. package/.next/server/app/dashboard/basic-chat.meta +0 -36
  530. package/.next/server/app/dashboard/basic-chat.rsc +0 -26
  531. package/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +0 -31
  532. package/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +0 -26
  533. package/.next/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +0 -6
  534. package/.next/static/C423Aljus-j0GJlKCHgC1/_buildManifest.js +0 -1
  535. package/.next/static/chunks/1278-3b5ed69340ddb23f.js +0 -1
  536. package/.next/static/chunks/1471-69a7c30abf98c656.js +0 -1
  537. package/.next/static/chunks/159-89c77cec422bd76f.js +0 -1
  538. package/.next/static/chunks/2392-b07fcae4714087ef.js +0 -65
  539. package/.next/static/chunks/2441-96064c4ee1216099.js +0 -1
  540. package/.next/static/chunks/5113-5c4f5181388aab72.js +0 -1
  541. package/.next/static/chunks/5778-9d97ce04f2ac118c.js +0 -1
  542. package/.next/static/chunks/6920-e2b533c1eafa9521.js +0 -1
  543. package/.next/static/chunks/7835-c1ef8f5cdaaad483.js +0 -1
  544. package/.next/static/chunks/9320-ae7eb68edeb92e89.js +0 -3
  545. package/.next/static/chunks/app/(dashboard)/dashboard/basic-chat/page-34f4d77aa3df67a8.js +0 -1
  546. package/.next/static/chunks/app/(dashboard)/dashboard/console-log/page-52b5a6dc2c2d2d93.js +0 -1
  547. package/.next/static/chunks/app/(dashboard)/dashboard/endpoint/page-9287a3cbd098b9c4.js +0 -1
  548. package/.next/static/chunks/app/(dashboard)/dashboard/page-1d6e969653676c7d.js +0 -1
  549. package/.next/static/chunks/app/_global-error/page-a826a2eb5dc30149.js +0 -1
  550. package/.next/static/chunks/app/api/auth/login/route-a826a2eb5dc30149.js +0 -1
  551. package/.next/static/chunks/app/api/auth/logout/route-a826a2eb5dc30149.js +0 -1
  552. package/.next/static/chunks/app/api/auth/oidc/callback/route-a826a2eb5dc30149.js +0 -1
  553. package/.next/static/chunks/app/api/auth/oidc/start/route-a826a2eb5dc30149.js +0 -1
  554. package/.next/static/chunks/app/api/auth/oidc/test/route-a826a2eb5dc30149.js +0 -1
  555. package/.next/static/chunks/app/api/auth/reset-password/route-a826a2eb5dc30149.js +0 -1
  556. package/.next/static/chunks/app/api/auth/saml/acs/route-a826a2eb5dc30149.js +0 -1
  557. package/.next/static/chunks/app/api/auth/saml/metadata/route-a826a2eb5dc30149.js +0 -1
  558. package/.next/static/chunks/app/api/auth/saml/start/route-a826a2eb5dc30149.js +0 -1
  559. package/.next/static/chunks/app/api/auth/saml/test/route-a826a2eb5dc30149.js +0 -1
  560. package/.next/static/chunks/app/api/auth/status/route-a826a2eb5dc30149.js +0 -1
  561. package/.next/static/chunks/app/api/changelog/route-a826a2eb5dc30149.js +0 -1
  562. package/.next/static/chunks/app/api/cli-tools/all-statuses/route-a826a2eb5dc30149.js +0 -1
  563. package/.next/static/chunks/app/api/cli-tools/claude-settings/route-a826a2eb5dc30149.js +0 -1
  564. package/.next/static/chunks/app/api/cli-tools/codex-settings/route-a826a2eb5dc30149.js +0 -1
  565. package/.next/static/chunks/app/api/cli-tools/cowork-mcp-registry/route-a826a2eb5dc30149.js +0 -1
  566. package/.next/static/chunks/app/api/cli-tools/cowork-mcp-tools/route-a826a2eb5dc30149.js +0 -1
  567. package/.next/static/chunks/app/api/cli-tools/cowork-settings/route-a826a2eb5dc30149.js +0 -1
  568. package/.next/static/chunks/app/api/cli-tools/dsh-settings/route-a826a2eb5dc30149.js +0 -1
  569. package/.next/static/chunks/app/api/cli-tools/opencode-settings/route-a826a2eb5dc30149.js +0 -1
  570. package/.next/static/chunks/app/api/combos/[id]/route-a826a2eb5dc30149.js +0 -1
  571. package/.next/static/chunks/app/api/combos/route-a826a2eb5dc30149.js +0 -1
  572. package/.next/static/chunks/app/api/dashboard/chat/completions/route-a826a2eb5dc30149.js +0 -1
  573. package/.next/static/chunks/app/api/headroom/extras/route-a826a2eb5dc30149.js +0 -1
  574. package/.next/static/chunks/app/api/headroom/proxy/[...path]/route-a826a2eb5dc30149.js +0 -1
  575. package/.next/static/chunks/app/api/headroom/restart/route-a826a2eb5dc30149.js +0 -1
  576. package/.next/static/chunks/app/api/headroom/start/route-a826a2eb5dc30149.js +0 -1
  577. package/.next/static/chunks/app/api/headroom/status/route-a826a2eb5dc30149.js +0 -1
  578. package/.next/static/chunks/app/api/headroom/stop/route-a826a2eb5dc30149.js +0 -1
  579. package/.next/static/chunks/app/api/health/route-a826a2eb5dc30149.js +0 -1
  580. package/.next/static/chunks/app/api/init/route-a826a2eb5dc30149.js +0 -1
  581. package/.next/static/chunks/app/api/keys/[id]/route-a826a2eb5dc30149.js +0 -1
  582. package/.next/static/chunks/app/api/keys/route-a826a2eb5dc30149.js +0 -1
  583. package/.next/static/chunks/app/api/locale/route-a826a2eb5dc30149.js +0 -1
  584. package/.next/static/chunks/app/api/mcp/[plugin]/message/route-a826a2eb5dc30149.js +0 -1
  585. package/.next/static/chunks/app/api/mcp/[plugin]/sse/route-a826a2eb5dc30149.js +0 -1
  586. package/.next/static/chunks/app/api/media-providers/tts/deepgram/voices/route-a826a2eb5dc30149.js +0 -1
  587. package/.next/static/chunks/app/api/media-providers/tts/elevenlabs/voices/route-a826a2eb5dc30149.js +0 -1
  588. package/.next/static/chunks/app/api/media-providers/tts/inworld/voices/route-a826a2eb5dc30149.js +0 -1
  589. package/.next/static/chunks/app/api/media-providers/tts/minimax/voices/route-a826a2eb5dc30149.js +0 -1
  590. package/.next/static/chunks/app/api/media-providers/tts/voices/route-a826a2eb5dc30149.js +0 -1
  591. package/.next/static/chunks/app/api/models/alias/route-a826a2eb5dc30149.js +0 -1
  592. package/.next/static/chunks/app/api/models/availability/route-a826a2eb5dc30149.js +0 -1
  593. package/.next/static/chunks/app/api/models/catalog-sync/route-a826a2eb5dc30149.js +0 -1
  594. package/.next/static/chunks/app/api/models/custom/route-a826a2eb5dc30149.js +0 -1
  595. package/.next/static/chunks/app/api/models/disabled/route-a826a2eb5dc30149.js +0 -1
  596. package/.next/static/chunks/app/api/models/route-a826a2eb5dc30149.js +0 -1
  597. package/.next/static/chunks/app/api/models/test/route-a826a2eb5dc30149.js +0 -1
  598. package/.next/static/chunks/app/api/oauth/[provider]/[action]/route-a826a2eb5dc30149.js +0 -1
  599. package/.next/static/chunks/app/api/oauth/codex/bulk-import/route-a826a2eb5dc30149.js +0 -1
  600. package/.next/static/chunks/app/api/oauth/codex/import-token/route-a826a2eb5dc30149.js +0 -1
  601. package/.next/static/chunks/app/api/oauth/cursor/auto-import/route-a826a2eb5dc30149.js +0 -1
  602. package/.next/static/chunks/app/api/oauth/cursor/import/route-a826a2eb5dc30149.js +0 -1
  603. package/.next/static/chunks/app/api/oauth/gitlab/pat/route-a826a2eb5dc30149.js +0 -1
  604. package/.next/static/chunks/app/api/oauth/grok-cli/bulk-import/route-a826a2eb5dc30149.js +0 -1
  605. package/.next/static/chunks/app/api/oauth/iflow/cookie/route-a826a2eb5dc30149.js +0 -1
  606. package/.next/static/chunks/app/api/oauth/xiaomi-mimo/api-key/route-a826a2eb5dc30149.js +0 -1
  607. package/.next/static/chunks/app/api/oauth/xiaomi-mimo/auto-import/route-a826a2eb5dc30149.js +0 -1
  608. package/.next/static/chunks/app/api/pricing/route-a826a2eb5dc30149.js +0 -1
  609. package/.next/static/chunks/app/api/provider-nodes/[id]/route-a826a2eb5dc30149.js +0 -1
  610. package/.next/static/chunks/app/api/provider-nodes/route-a826a2eb5dc30149.js +0 -1
  611. package/.next/static/chunks/app/api/provider-nodes/validate/route-a826a2eb5dc30149.js +0 -1
  612. package/.next/static/chunks/app/api/providers/[id]/models/route-a826a2eb5dc30149.js +0 -1
  613. package/.next/static/chunks/app/api/providers/[id]/route-a826a2eb5dc30149.js +0 -1
  614. package/.next/static/chunks/app/api/providers/[id]/test/route-a826a2eb5dc30149.js +0 -1
  615. package/.next/static/chunks/app/api/providers/[id]/test-models/route-a826a2eb5dc30149.js +0 -1
  616. package/.next/static/chunks/app/api/providers/client/route-a826a2eb5dc30149.js +0 -1
  617. package/.next/static/chunks/app/api/providers/kilo/free-models/route-a826a2eb5dc30149.js +0 -1
  618. package/.next/static/chunks/app/api/providers/route-a826a2eb5dc30149.js +0 -1
  619. package/.next/static/chunks/app/api/providers/suggested-models/route-a826a2eb5dc30149.js +0 -1
  620. package/.next/static/chunks/app/api/providers/test-batch/route-a826a2eb5dc30149.js +0 -1
  621. package/.next/static/chunks/app/api/providers/validate/route-a826a2eb5dc30149.js +0 -1
  622. package/.next/static/chunks/app/api/proxy-pools/[id]/route-a826a2eb5dc30149.js +0 -1
  623. package/.next/static/chunks/app/api/proxy-pools/[id]/test/route-a826a2eb5dc30149.js +0 -1
  624. package/.next/static/chunks/app/api/proxy-pools/cloudflare-deploy/route-a826a2eb5dc30149.js +0 -1
  625. package/.next/static/chunks/app/api/proxy-pools/deno-deploy/route-a826a2eb5dc30149.js +0 -1
  626. package/.next/static/chunks/app/api/proxy-pools/route-a826a2eb5dc30149.js +0 -1
  627. package/.next/static/chunks/app/api/proxy-pools/vercel-deploy/route-a826a2eb5dc30149.js +0 -1
  628. package/.next/static/chunks/app/api/pxpipe/health/route-a826a2eb5dc30149.js +0 -1
  629. package/.next/static/chunks/app/api/pxpipe/install/route-a826a2eb5dc30149.js +0 -1
  630. package/.next/static/chunks/app/api/pxpipe/logs/route-a826a2eb5dc30149.js +0 -1
  631. package/.next/static/chunks/app/api/pxpipe/restart/route-a826a2eb5dc30149.js +0 -1
  632. package/.next/static/chunks/app/api/pxpipe/start/route-a826a2eb5dc30149.js +0 -1
  633. package/.next/static/chunks/app/api/pxpipe/stats/route-a826a2eb5dc30149.js +0 -1
  634. package/.next/static/chunks/app/api/pxpipe/status/route-a826a2eb5dc30149.js +0 -1
  635. package/.next/static/chunks/app/api/pxpipe/stop/route-a826a2eb5dc30149.js +0 -1
  636. package/.next/static/chunks/app/api/settings/database/route-a826a2eb5dc30149.js +0 -1
  637. package/.next/static/chunks/app/api/settings/proxy-test/route-a826a2eb5dc30149.js +0 -1
  638. package/.next/static/chunks/app/api/settings/require-login/route-a826a2eb5dc30149.js +0 -1
  639. package/.next/static/chunks/app/api/settings/route-a826a2eb5dc30149.js +0 -1
  640. package/.next/static/chunks/app/api/shutdown/route-a826a2eb5dc30149.js +0 -1
  641. package/.next/static/chunks/app/api/tags/route-a826a2eb5dc30149.js +0 -1
  642. package/.next/static/chunks/app/api/translator/console-logs/route-a826a2eb5dc30149.js +0 -1
  643. package/.next/static/chunks/app/api/translator/console-logs/stream/route-a826a2eb5dc30149.js +0 -1
  644. package/.next/static/chunks/app/api/translator/load/route-a826a2eb5dc30149.js +0 -1
  645. package/.next/static/chunks/app/api/translator/save/route-a826a2eb5dc30149.js +0 -1
  646. package/.next/static/chunks/app/api/translator/send/route-a826a2eb5dc30149.js +0 -1
  647. package/.next/static/chunks/app/api/translator/translate/route-a826a2eb5dc30149.js +0 -1
  648. package/.next/static/chunks/app/api/tunnel/disable/route-a826a2eb5dc30149.js +0 -1
  649. package/.next/static/chunks/app/api/tunnel/enable/route-a826a2eb5dc30149.js +0 -1
  650. package/.next/static/chunks/app/api/tunnel/status/route-a826a2eb5dc30149.js +0 -1
  651. package/.next/static/chunks/app/api/tunnel/tailscale-check/route-a826a2eb5dc30149.js +0 -1
  652. package/.next/static/chunks/app/api/tunnel/tailscale-disable/route-a826a2eb5dc30149.js +0 -1
  653. package/.next/static/chunks/app/api/tunnel/tailscale-enable/route-a826a2eb5dc30149.js +0 -1
  654. package/.next/static/chunks/app/api/tunnel/tailscale-install/route-a826a2eb5dc30149.js +0 -1
  655. package/.next/static/chunks/app/api/usage/[connectionId]/codex-reset-credits/route-a826a2eb5dc30149.js +0 -1
  656. package/.next/static/chunks/app/api/usage/[connectionId]/route-a826a2eb5dc30149.js +0 -1
  657. package/.next/static/chunks/app/api/usage/chart/route-a826a2eb5dc30149.js +0 -1
  658. package/.next/static/chunks/app/api/usage/health/route-a826a2eb5dc30149.js +0 -1
  659. package/.next/static/chunks/app/api/usage/history/route-a826a2eb5dc30149.js +0 -1
  660. package/.next/static/chunks/app/api/usage/logs/route-a826a2eb5dc30149.js +0 -1
  661. package/.next/static/chunks/app/api/usage/providers/route-a826a2eb5dc30149.js +0 -1
  662. package/.next/static/chunks/app/api/usage/request-details/route-a826a2eb5dc30149.js +0 -1
  663. package/.next/static/chunks/app/api/usage/request-logs/route-a826a2eb5dc30149.js +0 -1
  664. package/.next/static/chunks/app/api/usage/stats/route-a826a2eb5dc30149.js +0 -1
  665. package/.next/static/chunks/app/api/usage/stream/route-a826a2eb5dc30149.js +0 -1
  666. package/.next/static/chunks/app/api/v1/api/chat/route-a826a2eb5dc30149.js +0 -1
  667. package/.next/static/chunks/app/api/v1/audio/speech/route-a826a2eb5dc30149.js +0 -1
  668. package/.next/static/chunks/app/api/v1/audio/transcriptions/route-a826a2eb5dc30149.js +0 -1
  669. package/.next/static/chunks/app/api/v1/audio/voices/route-a826a2eb5dc30149.js +0 -1
  670. package/.next/static/chunks/app/api/v1/chat/completions/route-a826a2eb5dc30149.js +0 -1
  671. package/.next/static/chunks/app/api/v1/embeddings/route-a826a2eb5dc30149.js +0 -1
  672. package/.next/static/chunks/app/api/v1/images/generations/route-a826a2eb5dc30149.js +0 -1
  673. package/.next/static/chunks/app/api/v1/messages/count_tokens/route-a826a2eb5dc30149.js +0 -1
  674. package/.next/static/chunks/app/api/v1/messages/route-a826a2eb5dc30149.js +0 -1
  675. package/.next/static/chunks/app/api/v1/models/[...model]/route-a826a2eb5dc30149.js +0 -1
  676. package/.next/static/chunks/app/api/v1/models/info/route-a826a2eb5dc30149.js +0 -1
  677. package/.next/static/chunks/app/api/v1/models/route-a826a2eb5dc30149.js +0 -1
  678. package/.next/static/chunks/app/api/v1/responses/compact/route-a826a2eb5dc30149.js +0 -1
  679. package/.next/static/chunks/app/api/v1/responses/route-a826a2eb5dc30149.js +0 -1
  680. package/.next/static/chunks/app/api/v1/route-a826a2eb5dc30149.js +0 -1
  681. package/.next/static/chunks/app/api/v1/search/route-a826a2eb5dc30149.js +0 -1
  682. package/.next/static/chunks/app/api/v1/systemone/route-a826a2eb5dc30149.js +0 -1
  683. package/.next/static/chunks/app/api/v1/videos/[id]/route-a826a2eb5dc30149.js +0 -1
  684. package/.next/static/chunks/app/api/v1/videos/edits/route-a826a2eb5dc30149.js +0 -1
  685. package/.next/static/chunks/app/api/v1/videos/extensions/route-a826a2eb5dc30149.js +0 -1
  686. package/.next/static/chunks/app/api/v1/videos/generations/route-a826a2eb5dc30149.js +0 -1
  687. package/.next/static/chunks/app/api/v1/web/fetch/route-a826a2eb5dc30149.js +0 -1
  688. package/.next/static/chunks/app/api/v1beta/models/[...path]/route-a826a2eb5dc30149.js +0 -1
  689. package/.next/static/chunks/app/api/v1beta/models/route-a826a2eb5dc30149.js +0 -1
  690. package/.next/static/chunks/app/api/version/route-a826a2eb5dc30149.js +0 -1
  691. package/.next/static/chunks/app/api/version/shutdown/route-a826a2eb5dc30149.js +0 -1
  692. package/.next/static/chunks/app/api/version/update/route-a826a2eb5dc30149.js +0 -1
  693. package/.next/static/chunks/app/callback/page-f714c2306a1e9004.js +0 -1
  694. package/.next/static/chunks/app/dashboard/settings/pricing/page-86197107690a0580.js +0 -1
  695. package/.next/static/chunks/app/landing/page-7a83d1be493ddc8c.js +0 -1
  696. package/.next/static/chunks/app/layout-f34e075b1872747e.js +0 -1
  697. package/.next/static/chunks/app/manifest.webmanifest/route-a826a2eb5dc30149.js +0 -1
  698. package/.next/static/chunks/app/page-a826a2eb5dc30149.js +0 -1
  699. package/.next/static/chunks/next/dist/client/components/builtin/app-error-a826a2eb5dc30149.js +0 -1
  700. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-a826a2eb5dc30149.js +0 -1
  701. package/.next/static/chunks/next/dist/client/components/builtin/not-found-a826a2eb5dc30149.js +0 -1
  702. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-a826a2eb5dc30149.js +0 -1
  703. package/.next/static/css/a2628e64fa8ac12e.css +0 -1
  704. package/src/app/(dashboard)/dashboard/basic-chat/BasicChatPageClient.tsx +0 -1178
  705. package/src/app/(dashboard)/dashboard/basic-chat/page.tsx +0 -5
  706. package/src/app/api/dashboard/chat/completions/route.ts +0 -45
  707. /package/.next/static/{C423Aljus-j0GJlKCHgC1 → 8QVpvFFKxoB53L449Kgan}/_ssgManifest.js +0 -0
@@ -1,1178 +0,0 @@
1
- "use client";
2
- import Icon from "@/shared/components/Icon";
3
-
4
- import { useEffect, useMemo, useRef, useState } from "react";
5
- import DOMPurify from "dompurify";
6
- import { marked } from "marked";
7
- import { Badge } from "@/components/ui/badge";
8
- import { Button } from "@/components/ui/button";
9
- import { getModelsByProviderId } from "@/shared/constants/models";
10
- import {
11
- isAnthropicCompatibleProvider,
12
- isOpenAICompatibleProvider,
13
- } from "@/shared/constants/providers";
14
-
15
- marked.setOptions({ gfm: true, breaks: true });
16
-
17
- const STORAGE_KEYS = {
18
- sessions: "basic-chat.sessions",
19
- activeSessionId: "basic-chat.activeSessionId",
20
- activeProviderId: "basic-chat.activeProviderId",
21
- draft: "basic-chat.draft",
22
- };
23
-
24
- function createId() {
25
- if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID();
26
- return `chat_${Date.now()}_${Math.random().toString(16).slice(2)}`;
27
- }
28
-
29
- function safeParse(value, fallback) {
30
- try {
31
- return JSON.parse(value);
32
- } catch {
33
- return fallback;
34
- }
35
- }
36
-
37
- function textValue(value) {
38
- if (typeof value === "string") return value;
39
- if (value == null) return "";
40
- if (Array.isArray(value)) return value.map(textValue).filter(Boolean).join(" ");
41
- if (typeof value === "object") {
42
- if (typeof value.message === "string") return value.message;
43
- if (typeof value.error === "string") return value.error;
44
- try {
45
- return JSON.stringify(value);
46
- } catch {
47
- return String(value);
48
- }
49
- }
50
- return String(value);
51
- }
52
-
53
- function humanize(value = "") {
54
- return (
55
- String(value)
56
- .replace(/[-_]/g, " ")
57
- .replace(/\b\w/g, (char) => char.toUpperCase())
58
- .trim() || "Unknown"
59
- );
60
- }
61
-
62
- function formatRelativeTime(value) {
63
- if (!value) return "Now";
64
- const time = new Date(value).getTime();
65
- if (Number.isNaN(time)) return "Now";
66
- const diffMinutes = Math.max(1, Math.round((Date.now() - time) / 60000));
67
- if (diffMinutes < 60) return `${diffMinutes}m`;
68
- const diffHours = Math.round(diffMinutes / 60);
69
- if (diffHours < 24) return `${diffHours}h`;
70
- return `${Math.round(diffHours / 24)}d`;
71
- }
72
-
73
- function makeSessionTitle(text = "") {
74
- const normalized = textValue(text).replace(/\s+/g, " ").trim();
75
- if (!normalized) return "New chat";
76
- return normalized.length > 52 ? `${normalized.slice(0, 52).trimEnd()}…` : normalized;
77
- }
78
-
79
- function buildUserContent(message) {
80
- const text = textValue(message.content).trim();
81
- const attachments = Array.isArray(message.attachments) ? message.attachments : [];
82
-
83
- if (attachments.length === 0) return text;
84
-
85
- const content = [];
86
- if (text) content.push({ type: "text", text });
87
-
88
- for (const attachment of attachments) {
89
- if (attachment?.dataUrl) {
90
- content.push({ type: "image_url", image_url: { url: attachment.dataUrl } });
91
- }
92
- }
93
-
94
- return content.length > 0 ? content : text;
95
- }
96
-
97
- function readAssistantText(chunk) {
98
- if (!chunk || typeof chunk !== "object") return "";
99
- const choice = chunk.choices?.[0];
100
- const delta = choice?.delta || {};
101
- const pieces = [delta.content, choice?.message?.content, chunk.output_text, chunk.text]
102
- .map(textValue)
103
- .filter(Boolean);
104
- return pieces[0] || "";
105
- }
106
-
107
- // Errors arrive as SSE events (`{ error }` or a Responses-style `{ type: "error" }`)
108
- // with no choices; the content-only parse would drop them and end the turn empty.
109
- function readChunkError(chunk) {
110
- if (!chunk || typeof chunk !== "object") return "";
111
- if (chunk.error) return textValue(chunk.error) || "Request failed";
112
- if (chunk.type === "error") return textValue(chunk.message) || "Request failed";
113
- return "";
114
- }
115
-
116
- function MarkdownMessage({ text }) {
117
- const raw = textValue(text);
118
- const html = useMemo(() => {
119
- if (!raw) return "";
120
- // DOMPurify needs a DOM; the server render has none (sessions hydrate from storage).
121
- if (typeof window === "undefined") return null;
122
- return DOMPurify.sanitize(marked.parse(raw, { async: false }));
123
- }, [raw]);
124
-
125
- if (html === null) return <span className="whitespace-pre-wrap break-words">{raw}</span>;
126
- return <div className="chat-markdown break-words" dangerouslySetInnerHTML={{ __html: html }} />;
127
- }
128
-
129
- async function fileToDataUrl(file) {
130
- return await new Promise((resolve, reject) => {
131
- const reader = new FileReader();
132
- reader.onload = () => resolve(String(reader.result || ""));
133
- reader.onerror = () => reject(reader.error || new Error("Failed to read file"));
134
- reader.readAsDataURL(file);
135
- });
136
- }
137
-
138
- function cloneSession(session) {
139
- return {
140
- ...session,
141
- messages: Array.isArray(session.messages)
142
- ? session.messages.map((message) => ({ ...message }))
143
- : [],
144
- };
145
- }
146
-
147
- function getProviderLabel(connection) {
148
- return connection?.name || humanize(connection?.provider || connection?.id || "provider");
149
- }
150
-
151
- function normalizeStaticModel(model, connection) {
152
- if (!model?.id) return null;
153
- return {
154
- id: `${connection.provider}/${model.id}`,
155
- requestModel: `${connection.provider}/${model.id}`,
156
- name: model.name || model.id,
157
- providerId: connection.provider,
158
- providerName: getProviderLabel(connection),
159
- source: "static",
160
- };
161
- }
162
-
163
- function normalizeLiveModel(model, connection) {
164
- const rawId = typeof model === "string" ? model : model?.id || model?.name || model?.model || "";
165
- if (!rawId) return null;
166
-
167
- const displayName =
168
- typeof model === "string" ? model : model?.name || model?.displayName || rawId;
169
-
170
- let requestModel = rawId;
171
- const isCompatible =
172
- isOpenAICompatibleProvider(connection.provider) ||
173
- isAnthropicCompatibleProvider(connection.provider);
174
- if (isCompatible && !rawId.includes("/")) {
175
- requestModel = `${connection.provider}/${rawId}`;
176
- }
177
-
178
- return {
179
- id: requestModel,
180
- requestModel,
181
- name: displayName,
182
- providerId: connection.provider,
183
- providerName: getProviderLabel(connection),
184
- source: "live",
185
- };
186
- }
187
-
188
- function parseProviderModelsPayload(data) {
189
- if (Array.isArray(data?.models)) return data.models;
190
- if (Array.isArray(data?.data)) return data.data;
191
- if (Array.isArray(data?.results)) return data.results;
192
- if (Array.isArray(data)) return data;
193
- return [];
194
- }
195
-
196
- function dedupeModels(models) {
197
- const map = new Map();
198
- for (const model of models) {
199
- if (!model?.id) continue;
200
- if (!map.has(model.id)) map.set(model.id, model);
201
- }
202
- return Array.from(map.values());
203
- }
204
-
205
- export default function BasicChatPageClient() {
206
- const [providerGroups, setProviderGroups] = useState<any[]>([]);
207
- const [loadingData, setLoadingData] = useState<boolean>(true);
208
- const [loadError, setLoadError] = useState<string>("");
209
- const [sessions, setSessions] = useState(() => {
210
- if (typeof window === "undefined") return [];
211
- try {
212
- const saved = safeParse(globalThis.localStorage.getItem(STORAGE_KEYS.sessions), []);
213
- return Array.isArray(saved)
214
- ? saved.map((session) => ({
215
- ...session,
216
- messages: Array.isArray(session.messages) ? session.messages : [],
217
- }))
218
- : [];
219
- } catch {
220
- return [];
221
- }
222
- });
223
- const [activeSessionId, setActiveSessionId] = useState(() => {
224
- if (typeof window === "undefined") return "";
225
- return globalThis.localStorage.getItem(STORAGE_KEYS.activeSessionId) || "";
226
- });
227
- const [activeProviderId, setActiveProviderId] = useState(() => {
228
- if (typeof window === "undefined") return "";
229
- return globalThis.localStorage.getItem(STORAGE_KEYS.activeProviderId) || "";
230
- });
231
- const [activeModelId, setActiveModelId] = useState<string>("");
232
- const [draft, setDraft] = useState(() => {
233
- if (typeof window === "undefined") return "";
234
- return globalThis.localStorage.getItem(STORAGE_KEYS.draft) || "";
235
- });
236
- const [attachments, setAttachments] = useState<any[]>([]);
237
- const [isSending, setIsSending] = useState<boolean>(false);
238
- const [streamingMessageId, setStreamingMessageId] = useState<string>("");
239
- const [streamingText, setStreamingText] = useState<string>("");
240
- const [isHydrated, setIsHydrated] = useState<boolean>(false);
241
- const [modelMenuOpen, setModelMenuOpen] = useState<boolean>(false);
242
- const [historyOpen, setHistoryOpen] = useState<boolean>(false);
243
- const fileInputRef = useRef<any>(null);
244
- const abortRef = useRef<any>(null);
245
- const initializedRef = useRef<boolean>(false);
246
- const modelMenuRef = useRef<any>(null);
247
- const historyMenuRef = useRef<any>(null);
248
-
249
- useEffect(() => {
250
- setIsHydrated(true);
251
- }, []);
252
-
253
- useEffect(() => {
254
- let cancelled = false;
255
-
256
- async function loadData() {
257
- setLoadingData(true);
258
- setLoadError("");
259
-
260
- try {
261
- const providersRes = await fetch("/api/providers", { cache: "no-store" });
262
- const providersData = await providersRes.json().catch(() => ({}));
263
- const connections = Array.isArray(providersData.connections)
264
- ? providersData.connections.filter((connection) => connection?.isActive !== false)
265
- : [];
266
-
267
- if (connections.length === 0) {
268
- if (!cancelled) {
269
- setProviderGroups([]);
270
- setLoadError("No providers connected yet.");
271
- }
272
- return;
273
- }
274
-
275
- const providerMap = new Map();
276
-
277
- for (const connection of connections) {
278
- const providerId = connection.provider || connection.id;
279
- const providerName = getProviderLabel(connection);
280
- const providerType = isOpenAICompatibleProvider(providerId)
281
- ? "openai-compatible"
282
- : isAnthropicCompatibleProvider(providerId)
283
- ? "anthropic-compatible"
284
- : providerId;
285
-
286
- if (!providerMap.has(providerId)) {
287
- providerMap.set(providerId, {
288
- providerId,
289
- providerName,
290
- providerType,
291
- connections: [],
292
- models: [],
293
- });
294
- }
295
-
296
- const group = providerMap.get(providerId);
297
- group.providerName = group.providerName || providerName;
298
- group.providerType = group.providerType || providerType;
299
- group.connections.push(connection);
300
-
301
- const staticModels = getModelsByProviderId(providerId)
302
- .map((model) => normalizeStaticModel(model, connection))
303
- .filter(Boolean);
304
- group.models.push(...staticModels);
305
- }
306
-
307
- const liveResults = await Promise.all(
308
- connections.map(async (connection) => {
309
- try {
310
- const response = await fetch(`/api/providers/${connection.id}/models`, {
311
- cache: "no-store",
312
- });
313
- const data = await response.json().catch(() => ({}));
314
- if (!response.ok) return { connection, models: [] };
315
- const models = parseProviderModelsPayload(data)
316
- .map((model) => normalizeLiveModel(model, connection))
317
- .filter(Boolean);
318
- return { connection, models };
319
- } catch {
320
- return { connection, models: [] };
321
- }
322
- }),
323
- );
324
-
325
- for (const result of liveResults) {
326
- const providerId = result.connection.provider || result.connection.id;
327
- const group = providerMap.get(providerId);
328
- if (!group) continue;
329
- group.models.push(...result.models);
330
- }
331
-
332
- const normalized = Array.from(providerMap.values())
333
- .map((group) => ({
334
- ...group,
335
- models: dedupeModels(group.models).sort((a, b) => a.name.localeCompare(b.name)),
336
- }))
337
- .filter((group) => group.models.length > 0)
338
- .sort((a, b) => a.providerName.localeCompare(b.providerName));
339
-
340
- if (!cancelled) {
341
- setProviderGroups(normalized);
342
- if (normalized.length === 0) {
343
- setLoadError("Providers connected but no models available.");
344
- }
345
- }
346
- } catch (error) {
347
- if (!cancelled) {
348
- setLoadError(textValue(error?.message) || "Failed to load providers/models.");
349
- setProviderGroups([]);
350
- }
351
- } finally {
352
- if (!cancelled) setLoadingData(false);
353
- }
354
- }
355
-
356
- loadData();
357
- return () => {
358
- cancelled = true;
359
- };
360
- }, []);
361
-
362
- useEffect(() => {
363
- const handleClickOutside = (event: any) => {
364
- if (modelMenuRef.current && !modelMenuRef.current.contains(event.target)) {
365
- setModelMenuOpen(false);
366
- }
367
- if (historyMenuRef.current && !historyMenuRef.current.contains(event.target)) {
368
- setHistoryOpen(false);
369
- }
370
- };
371
-
372
- document.addEventListener("mousedown", handleClickOutside);
373
- return () => document.removeEventListener("mousedown", handleClickOutside);
374
- }, []);
375
-
376
- const modelIndex = useMemo(() => {
377
- const map = new Map();
378
- for (const group of providerGroups) {
379
- for (const model of group.models) {
380
- map.set(model.id, {
381
- ...model,
382
- providerId: group.providerId,
383
- providerName: group.providerName,
384
- });
385
- }
386
- }
387
- return map;
388
- }, [providerGroups]);
389
-
390
- const activeProviderGroup = useMemo(() => {
391
- return (
392
- providerGroups.find((group) => group.providerId === activeProviderId) ||
393
- providerGroups[0] ||
394
- null
395
- );
396
- }, [providerGroups, activeProviderId]);
397
-
398
- const activeModel = useMemo(() => {
399
- if (activeModelId && modelIndex.has(activeModelId)) return modelIndex.get(activeModelId);
400
- if (activeSessionId) {
401
- const session = sessions.find((item) => item.id === activeSessionId);
402
- if (session?.modelId && modelIndex.has(session.modelId))
403
- return modelIndex.get(session.modelId);
404
- }
405
- return activeProviderGroup?.models?.[0] || null;
406
- }, [activeModelId, modelIndex, activeProviderGroup, sessions, activeSessionId]);
407
-
408
- const currentSession = useMemo(
409
- () => sessions.find((session) => session.id === activeSessionId) || null,
410
- [sessions, activeSessionId],
411
- );
412
- const currentMessages = currentSession?.messages || [];
413
- const sessionItems = useMemo(
414
- () =>
415
- [...sessions].sort(
416
- (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),
417
- ),
418
- [sessions],
419
- );
420
- const canSend =
421
- !isSending && !!activeModel && (draft.trim().length > 0 || attachments.length > 0);
422
-
423
- useEffect(() => {
424
- if (!isHydrated) return;
425
- try {
426
- globalThis.localStorage.setItem(STORAGE_KEYS.sessions, JSON.stringify(sessions));
427
- globalThis.localStorage.setItem(STORAGE_KEYS.activeSessionId, activeSessionId);
428
- globalThis.localStorage.setItem(STORAGE_KEYS.activeProviderId, activeProviderId);
429
- globalThis.localStorage.setItem(STORAGE_KEYS.draft, draft);
430
- } catch {
431
- // Ignore storage errors.
432
- }
433
- }, [isHydrated, sessions, activeSessionId, activeProviderId, draft]);
434
-
435
- useEffect(() => {
436
- if (!isHydrated || loadingData || initializedRef.current) return;
437
- if (providerGroups.length === 0) return;
438
-
439
- const savedProvider =
440
- providerGroups.find((group) => group.providerId === activeProviderId) || providerGroups[0];
441
- const savedModel =
442
- activeModelId && modelIndex.has(activeModelId)
443
- ? modelIndex.get(activeModelId)
444
- : savedProvider.models[0];
445
-
446
- if (sessions.length > 0) {
447
- const session = sessions.find((item) => item.id === activeSessionId) || sessions[0];
448
- const sessionModel =
449
- session?.modelId && modelIndex.has(session.modelId)
450
- ? modelIndex.get(session.modelId)
451
- : savedModel;
452
- initializedRef.current = true;
453
- setActiveSessionId(session.id);
454
- setActiveProviderId(sessionModel?.providerId || savedProvider.providerId);
455
- setActiveModelId(sessionModel?.id || savedModel.id);
456
- return;
457
- }
458
-
459
- const session = {
460
- id: createId(),
461
- title: "New chat",
462
- providerId: savedProvider.providerId,
463
- providerName: savedProvider.providerName,
464
- modelId: savedModel.id,
465
- modelName: savedModel.name,
466
- createdAt: new Date().toISOString(),
467
- updatedAt: new Date().toISOString(),
468
- messages: [],
469
- };
470
-
471
- initializedRef.current = true;
472
- setSessions([session]);
473
- setActiveSessionId(session.id);
474
- setActiveProviderId(savedProvider.providerId);
475
- setActiveModelId(savedModel.id);
476
- }, [
477
- isHydrated,
478
- loadingData,
479
- providerGroups,
480
- modelIndex,
481
- sessions,
482
- activeSessionId,
483
- activeProviderId,
484
- activeModelId,
485
- ]);
486
-
487
- const updateSession = (sessionId, updater) => {
488
- setSessions((prev) =>
489
- prev.map((session) => (session.id === sessionId ? updater(cloneSession(session)) : session)),
490
- );
491
- };
492
-
493
- const ensureSessionForModel = (model) => {
494
- if (!model) return null;
495
- return {
496
- id: createId(),
497
- title: "New chat",
498
- providerId: model.providerId,
499
- providerName: model.providerName,
500
- modelId: model.id,
501
- modelName: model.name,
502
- createdAt: new Date().toISOString(),
503
- updatedAt: new Date().toISOString(),
504
- messages: [],
505
- };
506
- };
507
-
508
- const handleNewChat = () => {
509
- if (!activeModel) return;
510
- const session = ensureSessionForModel(activeModel);
511
- if (!session) return;
512
- setSessions((prev) => [session, ...prev]);
513
- setActiveSessionId(session.id);
514
- setActiveProviderId(session.providerId);
515
- setActiveModelId(session.modelId);
516
- setDraft("");
517
- setAttachments([]);
518
- setStreamingMessageId("");
519
- setStreamingText("");
520
- };
521
-
522
- const handleSelectSession = (sessionId) => {
523
- const session = sessions.find((item) => item.id === sessionId);
524
- if (!session) return;
525
- setActiveSessionId(sessionId);
526
- setActiveProviderId(session.providerId || activeProviderId);
527
- setActiveModelId(session.modelId || activeModelId);
528
- setHistoryOpen(false);
529
- };
530
-
531
- const handleDeleteCurrentChat = () => {
532
- if (!activeSessionId) return;
533
- const nextSessions = sessions.filter((session) => session.id !== activeSessionId);
534
- const fallback = nextSessions[0] || null;
535
- setSessions(nextSessions);
536
- if (fallback) {
537
- setActiveSessionId(fallback.id);
538
- setActiveProviderId(fallback.providerId);
539
- setActiveModelId(fallback.modelId);
540
- } else {
541
- setActiveSessionId("");
542
- setActiveProviderId("");
543
- setActiveModelId("");
544
- }
545
- };
546
-
547
- const handleSelectProvider = (providerId) => {
548
- const group = providerGroups.find((item) => item.providerId === providerId);
549
- if (!group || group.models.length === 0) return;
550
- const nextModel = group.models[0];
551
-
552
- const current = sessions.find((session) => session.id === activeSessionId);
553
- if (current && current.messages.length > 0) {
554
- const session = ensureSessionForModel(nextModel);
555
- if (!session) return;
556
- setSessions((prev) => [session, ...prev]);
557
- setActiveSessionId(session.id);
558
- } else if (current) {
559
- setSessions((prev) =>
560
- prev.map((item) =>
561
- item.id === current.id
562
- ? {
563
- ...item,
564
- providerId: group.providerId,
565
- providerName: group.providerName,
566
- modelId: nextModel.id,
567
- modelName: nextModel.name,
568
- }
569
- : item,
570
- ),
571
- );
572
- setActiveSessionId(current.id);
573
- }
574
-
575
- setActiveProviderId(group.providerId);
576
- setActiveModelId(nextModel.id);
577
- setModelMenuOpen(false);
578
- };
579
-
580
- const handleSelectModel = (modelId) => {
581
- const model = modelIndex.get(modelId);
582
- if (!model) return;
583
-
584
- const current = sessions.find((session) => session.id === activeSessionId);
585
- if (current && current.messages.length > 0) {
586
- const session = ensureSessionForModel(model);
587
- if (!session) return;
588
- setSessions((prev) => [session, ...prev]);
589
- setActiveSessionId(session.id);
590
- } else if (current) {
591
- setSessions((prev) =>
592
- prev.map((item) =>
593
- item.id === current.id
594
- ? {
595
- ...item,
596
- providerId: model.providerId,
597
- providerName: model.providerName,
598
- modelId: model.id,
599
- modelName: model.name,
600
- }
601
- : item,
602
- ),
603
- );
604
- setActiveSessionId(current.id);
605
- } else {
606
- const session = ensureSessionForModel(model);
607
- if (!session) return;
608
- setSessions((prev) => [session, ...prev]);
609
- setActiveSessionId(session.id);
610
- }
611
-
612
- setActiveProviderId(model.providerId);
613
- setActiveModelId(model.id);
614
- setModelMenuOpen(false);
615
- };
616
-
617
- const handleAttachFiles = async (event: any) => {
618
- const files: any[] = Array.from(event.target.files || []);
619
- if (files.length === 0) return;
620
-
621
- const images = files.filter((file) => file.type.startsWith("image/"));
622
- if (images.length === 0) {
623
- event.target.value = "";
624
- return;
625
- }
626
-
627
- const converted = await Promise.all(
628
- images.map(async (file) => ({
629
- id: createId(),
630
- name: file.name,
631
- type: file.type,
632
- size: file.size,
633
- dataUrl: await fileToDataUrl(file),
634
- })),
635
- );
636
-
637
- setAttachments((prev) => [...prev, ...converted]);
638
- event.target.value = "";
639
- };
640
-
641
- const removeAttachment = (attachmentId) => {
642
- setAttachments((prev) => prev.filter((attachment) => attachment.id !== attachmentId));
643
- };
644
-
645
- const handleStop = () => {
646
- abortRef.current?.abort();
647
- };
648
-
649
- const finalizeSessionTitle = (sessionId, titleSeed) => {
650
- const title = makeSessionTitle(titleSeed);
651
- updateSession(sessionId, (session) => ({
652
- ...session,
653
- title: session.title === "New chat" ? title : session.title,
654
- updatedAt: new Date().toISOString(),
655
- }));
656
- };
657
-
658
- const sendMessage = async () => {
659
- const model = activeModel || activeProviderGroup?.models?.[0] || null;
660
- if (!model) return;
661
-
662
- const userText = draft.trim();
663
- if (!userText && attachments.length === 0) return;
664
-
665
- let sessionId = activeSessionId;
666
- let session = sessions.find((item) => item.id === sessionId);
667
- if (!session) {
668
- session = ensureSessionForModel(model);
669
- if (!session) return;
670
- sessionId = session.id;
671
- setSessions((prev) => [session, ...prev]);
672
- setActiveSessionId(sessionId);
673
- }
674
-
675
- const userMessage = {
676
- id: createId(),
677
- role: "user",
678
- content: userText,
679
- attachments: attachments.map((attachment) => ({
680
- id: attachment.id,
681
- name: attachment.name,
682
- type: attachment.type,
683
- dataUrl: attachment.dataUrl,
684
- })),
685
- createdAt: new Date().toISOString(),
686
- };
687
-
688
- const assistantMessageId = createId();
689
- const assistantMessage = {
690
- id: assistantMessageId,
691
- role: "assistant",
692
- content: "",
693
- createdAt: new Date().toISOString(),
694
- status: "streaming",
695
- };
696
-
697
- const nextMessages = [...(session.messages || []), userMessage, assistantMessage];
698
- setSessions((prev) =>
699
- prev.map((item) =>
700
- item.id === sessionId
701
- ? {
702
- ...item,
703
- providerId: model.providerId,
704
- providerName: model.providerName,
705
- modelId: model.id,
706
- modelName: model.name,
707
- messages: nextMessages,
708
- updatedAt: new Date().toISOString(),
709
- title: item.title === "New chat" ? makeSessionTitle(userText) : item.title,
710
- }
711
- : item,
712
- ),
713
- );
714
- setDraft("");
715
- setAttachments([]);
716
- setIsSending(true);
717
- setStreamingMessageId(assistantMessageId);
718
- setStreamingText("");
719
- abortRef.current?.abort();
720
- abortRef.current = new AbortController();
721
-
722
- const requestMessages = nextMessages
723
- .filter((message) => !(message.role === "assistant" && message.id === assistantMessageId))
724
- .map((message) => ({
725
- role: message.role,
726
- content: message.role === "user" ? buildUserContent(message) : message.content,
727
- }));
728
-
729
- try {
730
- const response = await fetch("/api/dashboard/chat/completions", {
731
- method: "POST",
732
- headers: {
733
- "Content-Type": "application/json",
734
- Accept: "text/event-stream",
735
- },
736
- body: JSON.stringify({
737
- model: model.requestModel || model.id,
738
- messages: requestMessages,
739
- stream: true,
740
- }),
741
- signal: abortRef.current.signal,
742
- });
743
-
744
- if (!response.ok) {
745
- const errorData = await response.json().catch(() => ({}));
746
- throw new Error(
747
- textValue(errorData.error || errorData.message || `Request failed (${response.status})`),
748
- );
749
- }
750
-
751
- const reader = response.body?.getReader();
752
- if (!reader) {
753
- const data = await response.json().catch(() => ({}));
754
- const fallbackText = textValue(
755
- data?.choices?.[0]?.message?.content ||
756
- data?.output_text ||
757
- data?.error ||
758
- data?.message ||
759
- "",
760
- );
761
- updateSession(sessionId, (currentSession) => ({
762
- ...currentSession,
763
- messages: currentSession.messages.map((message) =>
764
- message.id === assistantMessageId
765
- ? { ...message, content: fallbackText, status: "done" }
766
- : message,
767
- ),
768
- updatedAt: new Date().toISOString(),
769
- }));
770
- return;
771
- }
772
-
773
- const decoder = new TextDecoder();
774
- let buffer = "";
775
- let assistantText = "";
776
- let streamError = "";
777
-
778
- while (true) {
779
- const { value, done } = await reader.read();
780
- if (done) break;
781
-
782
- buffer += decoder.decode(value, { stream: true });
783
- const lines = buffer.split(/\r?\n/);
784
- buffer = lines.pop() || "";
785
-
786
- for (const line of lines) {
787
- const trimmed = line.trim();
788
- if (!trimmed.startsWith("data:")) continue;
789
-
790
- const payload = trimmed.slice(5).trim();
791
- if (!payload || payload === "[DONE]") continue;
792
-
793
- try {
794
- const chunk = JSON.parse(payload);
795
- const chunkError = readChunkError(chunk);
796
- if (chunkError) {
797
- streamError = chunkError;
798
- continue;
799
- }
800
-
801
- const text = readAssistantText(chunk);
802
- if (!text) continue;
803
-
804
- assistantText += text;
805
- setStreamingText(assistantText);
806
- updateSession(sessionId, (currentSession) => ({
807
- ...currentSession,
808
- messages: currentSession.messages.map((message) =>
809
- message.id === assistantMessageId
810
- ? { ...message, content: assistantText, status: "streaming" }
811
- : message,
812
- ),
813
- updatedAt: new Date().toISOString(),
814
- }));
815
- } catch {
816
- // Ignore malformed chunks.
817
- }
818
- }
819
- }
820
-
821
- updateSession(sessionId, (currentSession) => ({
822
- ...currentSession,
823
- messages: currentSession.messages.map((message) => {
824
- if (message.id !== assistantMessageId) return message;
825
- if (!assistantText && streamError) {
826
- return { ...message, content: message.content || streamError, status: "error" };
827
- }
828
- return { ...message, content: assistantText || message.content, status: "done" };
829
- }),
830
- updatedAt: new Date().toISOString(),
831
- }));
832
- if (!assistantText && streamError) setLoadError(streamError);
833
- finalizeSessionTitle(sessionId, userText);
834
- } catch (error) {
835
- if (error.name !== "AbortError") {
836
- const errorText = textValue(error?.message || error);
837
- updateSession(sessionId, (currentSession) => ({
838
- ...currentSession,
839
- messages: currentSession.messages.map((message) =>
840
- message.id === assistantMessageId
841
- ? { ...message, content: message.content || `Error: ${errorText}`, status: "error" }
842
- : message,
843
- ),
844
- updatedAt: new Date().toISOString(),
845
- }));
846
- setLoadError(errorText || "Failed to send message.");
847
- }
848
- } finally {
849
- setIsSending(false);
850
- setStreamingMessageId("");
851
- setStreamingText("");
852
- abortRef.current = null;
853
- }
854
- };
855
-
856
- const handleKeyDown = (event: any) => {
857
- if (event.key === "Enter" && !event.shiftKey) {
858
- event.preventDefault();
859
- if (canSend) sendMessage();
860
- }
861
- };
862
-
863
- const modelLabel = activeModel ? `${activeModel.name}` : "Select model";
864
- const modelSubLabel = activeModel ? activeModel.requestModel : "Choose from connected providers";
865
-
866
- return (
867
- <div className="relative flex-1 flex flex-col h-full min-h-0 min-w-0 bg-[#212121] text-white overflow-hidden">
868
- <div className="relative mx-auto flex flex-1 h-full min-h-0 w-full max-w-4xl flex-col">
869
- <div className="flex shrink-0 items-center justify-between gap-3 px-4 py-3 lg:px-6">
870
- <div ref={modelMenuRef} className="relative">
871
- <button
872
- type="button"
873
- onClick={() => setModelMenuOpen((value) => !value)}
874
- className="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-left transition hover:bg-white/8"
875
- >
876
- <div className="min-w-0">
877
- <div className="flex items-center gap-2">
878
- <span className="text-sm font-semibold text-white">{modelLabel}</span>
879
- <Icon name="expand_more" className="text-[18px] text-white/70" />
880
- </div>
881
- <p className="truncate text-xs text-white/55">{modelSubLabel}</p>
882
- </div>
883
- </button>
884
-
885
- {modelMenuOpen ? (
886
- <div className="absolute left-0 top-[calc(100%+10px)] z-30 w-[min(520px,calc(100vw-2rem))] overflow-hidden rounded-[20px] border border-white/10 bg-[#262626] shadow-2xl shadow-black/50">
887
- <div className="border-b border-white/10 px-4 py-3">
888
- <p className="text-xs uppercase tracking-[0.22em] text-white/45">Models</p>
889
- <p className="text-sm text-white/75">Only from connected providers</p>
890
- </div>
891
- <div className="max-h-[60vh] overflow-y-auto p-2">
892
- {providerGroups.map((group) => (
893
- <div
894
- key={group.providerId}
895
- className="mb-2 rounded-[16px] border border-white/10 bg-black/20 p-2"
896
- >
897
- <div className="flex items-center justify-between px-2 py-2">
898
- <p className="text-sm font-semibold text-white">{group.providerName}</p>
899
- <Badge>{group.models.length}</Badge>
900
- </div>
901
- <div className="grid gap-2 sm:grid-cols-2">
902
- {group.models.map((model) => {
903
- const isActive = model.id === activeModelId;
904
- return (
905
- <button
906
- key={model.id}
907
- type="button"
908
- onClick={() => handleSelectModel(model.id)}
909
- className={`rounded-[14px] border px-3 py-3 text-left transition ${isActive ? "border-blue-400/40 bg-blue-500/15" : "border-white/10 bg-white/5 hover:bg-white/8"}`}
910
- >
911
- <div className="flex items-start justify-between gap-3">
912
- <div className="min-w-0">
913
- <p className="truncate text-sm font-medium text-white">
914
- {model.name}
915
- </p>
916
- <p className="truncate text-[11px] text-white/45">
917
- {model.requestModel}
918
- </p>
919
- </div>
920
- {isActive ? (
921
- <Icon name="check_circle" className="text-[18px] text-blue-300" />
922
- ) : null}
923
- </div>
924
- </button>
925
- );
926
- })}
927
- </div>
928
- </div>
929
- ))}
930
- </div>
931
- </div>
932
- ) : null}
933
- </div>
934
-
935
- <div className="flex items-center gap-2">
936
- <button
937
- type="button"
938
- onClick={() => setHistoryOpen((value) => !value)}
939
- className="rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-white/80 transition hover:bg-white/8"
940
- >
941
- History
942
- </button>
943
- <Button
944
- variant="ghost"
945
- size="sm"
946
- onClick={handleDeleteCurrentChat}
947
- disabled={!activeSessionId || sessions.length === 0}
948
- >
949
- <Icon name="delete" />
950
- Clear
951
- </Button>
952
- </div>
953
- </div>
954
-
955
- {historyOpen ? (
956
- <div
957
- ref={historyMenuRef}
958
- className="absolute right-4 top-[72px] z-20 w-[min(360px,calc(100vw-2rem))] rounded-[20px] border border-white/10 bg-[#262626] p-2 shadow-2xl shadow-black/50 lg:right-6"
959
- >
960
- <div className="px-3 py-2">
961
- <p className="text-xs uppercase tracking-[0.22em] text-white/45">Recent chats</p>
962
- </div>
963
- <div className="max-h-[48vh] space-y-2 overflow-y-auto p-1">
964
- {sessionItems.length === 0 ? (
965
- <div className="rounded-[16px] border border-dashed border-white/10 bg-white/5 p-4 text-sm text-white/55">
966
- No conversations yet.
967
- </div>
968
- ) : (
969
- sessionItems.map((session) => {
970
- const isActive = session.id === activeSessionId;
971
- const latestMessage =
972
- [...(session.messages || [])]
973
- .reverse()
974
- .find((message) => message.role === "user") || session.messages?.[0];
975
- return (
976
- <button
977
- key={session.id}
978
- type="button"
979
- onClick={() => handleSelectSession(session.id)}
980
- className={`w-full rounded-[16px] border px-3 py-3 text-left transition ${isActive ? "border-blue-400/40 bg-blue-500/15" : "border-white/10 bg-white/5 hover:bg-white/8"}`}
981
- >
982
- <div className="flex items-start justify-between gap-3">
983
- <div className="min-w-0 flex-1">
984
- <p className="truncate text-sm font-medium text-white">{session.title}</p>
985
- <p className="mt-1 truncate text-xs text-white/50">
986
- {textValue(latestMessage?.content) || "Empty chat"}
987
- </p>
988
- </div>
989
- <span className="text-[10px] text-white/40 shrink-0">
990
- {formatRelativeTime(session.updatedAt)}
991
- </span>
992
- </div>
993
- </button>
994
- );
995
- })
996
- )}
997
- </div>
998
- </div>
999
- ) : null}
1000
-
1001
- {loadError ? (
1002
- <div className="mt-4 rounded-[18px] border border-rose-500/20 bg-rose-500/10 px-4 py-3 text-rose-100">
1003
- <div className="flex items-start gap-3">
1004
- <Icon name="error" className="text-[20px]" />
1005
- <p className="text-sm leading-6">{loadError}</p>
1006
- </div>
1007
- </div>
1008
- ) : null}
1009
-
1010
- <div className="flex flex-1 flex-col min-h-0">
1011
- <div className="flex-1 overflow-y-auto py-4">
1012
- {currentMessages.length === 0 ? (
1013
- <div className="flex min-h-[50vh] items-center justify-center px-4 text-center">
1014
- <div className="max-w-xl space-y-4">
1015
- <div className="mx-auto flex size-16 items-center justify-center rounded-[20px] border border-white/10 bg-white/5 text-white/80">
1016
- <Icon name="chat" className="text-[30px]" />
1017
- </div>
1018
- <div className="space-y-2">
1019
- <h2 className="text-2xl font-semibold text-white">Start a conversation</h2>
1020
- <p className="text-sm leading-6 text-white/60">
1021
- Simple chat interface to interact with any AI model from connected providers.
1022
- Select a model and start chatting!
1023
- </p>
1024
- </div>
1025
- </div>
1026
- </div>
1027
- ) : null}
1028
-
1029
- <div className="mx-auto flex w-full max-w-3xl flex-col gap-4 px-4">
1030
- {currentMessages.map((message) => {
1031
- const isUser = message.role === "user";
1032
- const isAssistant = message.role === "assistant";
1033
- const isStreaming =
1034
- isAssistant &&
1035
- message.id === streamingMessageId &&
1036
- message.status === "streaming";
1037
- const content = textValue(message.content) || (isAssistant ? streamingText : "");
1038
-
1039
- return (
1040
- <div
1041
- key={message.id}
1042
- className={`flex w-full ${isUser ? "justify-end" : "justify-start"} mb-6`}
1043
- >
1044
- <div
1045
- className={`max-w-[min(88%,42rem)] ${isUser ? "rounded-3xl bg-[#2f2f2f] px-5 py-3.5 text-white" : "text-white/90"}`}
1046
- >
1047
- <div className="mb-1 flex items-center justify-between gap-3">
1048
- <span className="text-xs font-semibold">
1049
- {isUser ? "You" : activeModel?.name || "Assistant"}
1050
- </span>
1051
- </div>
1052
-
1053
- {message.attachments?.length ? (
1054
- <div className="mb-3 grid grid-cols-2 gap-2 sm:grid-cols-3 mt-2">
1055
- {message.attachments.map((attachment) => (
1056
- <a
1057
- key={attachment.id}
1058
- href={attachment.dataUrl}
1059
- target="_blank"
1060
- rel="noreferrer"
1061
- className="overflow-hidden rounded-[18px] border border-white/10 bg-black/20"
1062
- >
1063
- <img
1064
- src={attachment.dataUrl}
1065
- alt={attachment.name}
1066
- className="h-28 w-full object-cover"
1067
- loading="lazy"
1068
- decoding="async"
1069
- />
1070
- </a>
1071
- ))}
1072
- </div>
1073
- ) : null}
1074
-
1075
- <div
1076
- className={`break-words text-[15px] leading-7 ${isAssistant ? "" : "whitespace-pre-wrap"}`}
1077
- >
1078
- {isAssistant ? <MarkdownMessage text={content} /> : content}
1079
- {isAssistant && isStreaming && !streamingText ? (
1080
- <span className="inline-block animate-pulse">▋</span>
1081
- ) : null}
1082
- </div>
1083
- </div>
1084
- </div>
1085
- );
1086
- })}
1087
- </div>
1088
- </div>
1089
-
1090
- <div className="shrink-0 pt-2">
1091
- {attachments.length > 0 ? (
1092
- <div className="mx-auto mb-3 flex w-full max-w-3xl flex-wrap gap-2 px-4">
1093
- {attachments.map((attachment) => (
1094
- <div
1095
- key={attachment.id}
1096
- className="flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-2"
1097
- >
1098
- <span className="text-xs text-white/80 max-w-[12rem] truncate">
1099
- {attachment.name}
1100
- </span>
1101
- <button
1102
- type="button"
1103
- onClick={() => removeAttachment(attachment.id)}
1104
- className="text-white/55 hover:text-white"
1105
- aria-label="Remove attachment"
1106
- >
1107
- <Icon name="close" className="text-[18px]" />
1108
- </button>
1109
- </div>
1110
- ))}
1111
- </div>
1112
- ) : null}
1113
-
1114
- <div className="mx-auto w-full max-w-3xl px-4 pb-2">
1115
- <div className="rounded-[26px] bg-[#2f2f2f] px-3 pt-3 pb-2 shadow-[0_0_15px_rgba(0,0,0,0.10)] ring-1 ring-white/5">
1116
- <textarea
1117
- value={draft}
1118
- onChange={(event: any) => setDraft(event.target.value)}
1119
- onKeyDown={handleKeyDown}
1120
- placeholder="Message AI"
1121
- rows={1}
1122
- className="w-full resize-none bg-transparent px-2 text-[15px] leading-6 text-white outline-none placeholder:text-white/40 max-h-[25vh] overflow-y-auto"
1123
- />
1124
-
1125
- <div className="mt-2 flex items-center justify-between gap-3">
1126
- <div className="flex items-center gap-2">
1127
- <button
1128
- type="button"
1129
- onClick={() => fileInputRef.current?.click()}
1130
- disabled={!activeModel || loadingData}
1131
- className="p-2 text-white/50 hover:text-white transition rounded-full hover:bg-white/5"
1132
- >
1133
- <Icon name="attach_file" className="text-[20px]" />
1134
- </button>
1135
- <input
1136
- ref={fileInputRef}
1137
- type="file"
1138
- accept="image/*"
1139
- multiple
1140
- className="hidden"
1141
- onChange={handleAttachFiles}
1142
- />
1143
- <span className="text-xs font-medium text-white/30 truncate max-w-[120px]">
1144
- {activeModel ? activeModel.name : "No model"}
1145
- </span>
1146
- </div>
1147
-
1148
- <div className="flex items-center gap-2">
1149
- {isSending ? (
1150
- <button
1151
- type="button"
1152
- onClick={handleStop}
1153
- className="p-2 text-white bg-white/10 hover:bg-white/20 transition rounded-full h-8 w-8 flex items-center justify-center"
1154
- >
1155
- <Icon name="stop" className="text-[16px]" />
1156
- </button>
1157
- ) : null}
1158
- <button
1159
- onClick={sendMessage}
1160
- disabled={!canSend}
1161
- className={`h-8 w-8 rounded-full flex items-center justify-center transition ${canSend ? "bg-white text-black hover:opacity-90" : "bg-white/10 text-white/30 cursor-not-allowed"}`}
1162
- >
1163
- <Icon name="arrow_upward" className="text-[16px]" />
1164
- </button>
1165
- </div>
1166
- </div>
1167
- </div>
1168
- </div>
1169
- </div>
1170
-
1171
- <p className="mx-auto mt-2 max-w-3xl px-4 pb-4 text-center text-[11px] text-white/30">
1172
- Model list is filtered from connected providers.
1173
- </p>
1174
- </div>
1175
- </div>
1176
- </div>
1177
- );
1178
- }