zevairouter 1.0.116 → 1.0.118

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 (346) hide show
  1. package/cli/app/.next-cli-build/BUILD_ID +1 -1
  2. package/cli/app/.next-cli-build/app-path-routes-manifest.json +9 -9
  3. package/cli/app/.next-cli-build/build-manifest.json +2 -2
  4. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/automation/page_client-reference-manifest.js +1 -1
  5. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
  6. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
  7. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
  8. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  9. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  10. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  11. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/context/page_client-reference-manifest.js +1 -1
  12. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  13. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
  14. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
  15. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
  16. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
  17. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  18. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  19. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
  20. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  21. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  22. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  23. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  24. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  25. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
  26. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  27. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/terminal/page_client-reference-manifest.js +1 -1
  28. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
  29. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  30. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  31. package/cli/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
  32. package/cli/app/.next-cli-build/server/app/_global-error.html +1 -1
  33. package/cli/app/.next-cli-build/server/app/_global-error.rsc +1 -1
  34. package/cli/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
  35. package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  36. package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  37. package/cli/app/.next-cli-build/server/app/_global-error.segments/_head.segment.rsc +1 -1
  38. package/cli/app/.next-cli-build/server/app/_global-error.segments/_index.segment.rsc +1 -1
  39. package/cli/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  40. package/cli/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
  41. package/cli/app/.next-cli-build/server/app/_not-found.html +1 -1
  42. package/cli/app/.next-cli-build/server/app/_not-found.rsc +3 -3
  43. package/cli/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +3 -3
  44. package/cli/app/.next-cli-build/server/app/_not-found.segments/_head.segment.rsc +1 -1
  45. package/cli/app/.next-cli-build/server/app/_not-found.segments/_index.segment.rsc +3 -3
  46. package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  47. package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  48. package/cli/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  49. package/cli/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js +1 -1
  50. package/cli/app/.next-cli-build/server/app/api/combos/[id]/route.js +1 -1
  51. package/cli/app/.next-cli-build/server/app/api/models/route.js +1 -1
  52. package/cli/app/.next-cli-build/server/app/api/models/test/route.js +1 -1
  53. package/cli/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js +1 -1
  54. package/cli/app/.next-cli-build/server/app/api/providers/route.js +1 -1
  55. package/cli/app/.next-cli-build/server/app/api/providers/validate/route.js +1 -1
  56. package/cli/app/.next-cli-build/server/app/api/settings/route.js +1 -1
  57. package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/input/route.js.nft.json +1 -1
  58. package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/resize/route.js.nft.json +1 -1
  59. package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/route.js.nft.json +1 -1
  60. package/cli/app/.next-cli-build/server/app/api/terminal/session/[id]/stream/route.js.nft.json +1 -1
  61. package/cli/app/.next-cli-build/server/app/api/terminal/session/route.js.nft.json +1 -1
  62. package/cli/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
  63. package/cli/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +1 -1
  64. package/cli/app/.next-cli-build/server/app/api/v1/audio/speech/route.js +1 -1
  65. package/cli/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js +1 -1
  66. package/cli/app/.next-cli-build/server/app/api/v1/embeddings/route.js +1 -1
  67. package/cli/app/.next-cli-build/server/app/api/v1/images/generations/route.js +1 -1
  68. package/cli/app/.next-cli-build/server/app/api/v1/messages/count_tokens/route.js +1 -1
  69. package/cli/app/.next-cli-build/server/app/api/v1/search/route.js +1 -1
  70. package/cli/app/.next-cli-build/server/app/api/v1/web/fetch/route.js +1 -1
  71. package/cli/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js +1 -1
  72. package/cli/app/.next-cli-build/server/app/api/version/route.js +1 -1
  73. package/cli/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
  74. package/cli/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
  75. package/cli/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
  76. package/cli/app/.next-cli-build/server/app/callback.html +1 -1
  77. package/cli/app/.next-cli-build/server/app/callback.rsc +3 -3
  78. package/cli/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +3 -3
  79. package/cli/app/.next-cli-build/server/app/callback.segments/_head.segment.rsc +1 -1
  80. package/cli/app/.next-cli-build/server/app/callback.segments/_index.segment.rsc +3 -3
  81. package/cli/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +1 -1
  82. package/cli/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
  83. package/cli/app/.next-cli-build/server/app/callback.segments/callback.segment.rsc +1 -1
  84. package/cli/app/.next-cli-build/server/app/dashboard/automation.html +1 -1
  85. package/cli/app/.next-cli-build/server/app/dashboard/automation.rsc +5 -5
  86. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation/__PAGE__.segment.rsc +2 -2
  87. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation.segment.rsc +1 -1
  88. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  89. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  90. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_full.segment.rsc +5 -5
  91. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_head.segment.rsc +1 -1
  92. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_index.segment.rsc +3 -3
  93. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_tree.segment.rsc +1 -1
  94. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
  95. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +5 -5
  96. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
  97. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
  98. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  99. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  100. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
  101. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
  102. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
  103. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
  104. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
  105. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +5 -5
  106. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
  107. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
  108. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  109. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  110. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
  111. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
  112. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
  113. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
  114. package/cli/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
  115. package/cli/app/.next-cli-build/server/app/dashboard/combos.rsc +5 -5
  116. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
  117. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
  118. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  119. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  120. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
  121. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
  122. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
  123. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
  124. package/cli/app/.next-cli-build/server/app/dashboard/context.html +1 -1
  125. package/cli/app/.next-cli-build/server/app/dashboard/context.rsc +5 -5
  126. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context/__PAGE__.segment.rsc +2 -2
  127. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context.segment.rsc +1 -1
  128. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  129. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  130. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_full.segment.rsc +5 -5
  131. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_head.segment.rsc +1 -1
  132. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_index.segment.rsc +3 -3
  133. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_tree.segment.rsc +1 -1
  134. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
  135. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.rsc +5 -5
  136. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
  137. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
  138. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  139. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  140. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
  141. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
  142. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
  143. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
  144. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
  145. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +5 -5
  146. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +2 -2
  147. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web.segment.rsc +1 -1
  148. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers.segment.rsc +1 -1
  149. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  150. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  151. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +5 -5
  152. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_head.segment.rsc +1 -1
  153. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_index.segment.rsc +3 -3
  154. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
  155. package/cli/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
  156. package/cli/app/.next-cli-build/server/app/dashboard/mitm.rsc +5 -5
  157. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
  158. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
  159. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  160. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  161. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
  162. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
  163. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
  164. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
  165. package/cli/app/.next-cli-build/server/app/dashboard/playground.html +1 -1
  166. package/cli/app/.next-cli-build/server/app/dashboard/playground.rsc +5 -5
  167. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground/__PAGE__.segment.rsc +2 -2
  168. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground.segment.rsc +1 -1
  169. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  170. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  171. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_full.segment.rsc +5 -5
  172. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_head.segment.rsc +1 -1
  173. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_index.segment.rsc +3 -3
  174. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_tree.segment.rsc +1 -1
  175. package/cli/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
  176. package/cli/app/.next-cli-build/server/app/dashboard/profile.rsc +5 -5
  177. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
  178. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
  179. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  180. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  181. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
  182. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
  183. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
  184. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
  185. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
  186. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.rsc +5 -5
  187. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
  188. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
  189. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  190. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  191. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  192. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
  193. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
  194. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
  195. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
  196. package/cli/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
  197. package/cli/app/.next-cli-build/server/app/dashboard/providers.rsc +5 -5
  198. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
  199. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  200. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  201. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  202. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
  203. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
  204. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
  205. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
  206. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
  207. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +5 -5
  208. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
  209. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
  210. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  211. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  212. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
  213. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
  214. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
  215. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
  216. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.html +1 -1
  217. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.rsc +5 -5
  218. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +2 -2
  219. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe.segment.rsc +1 -1
  220. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  221. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  222. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_full.segment.rsc +5 -5
  223. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_head.segment.rsc +1 -1
  224. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_index.segment.rsc +3 -3
  225. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +1 -1
  226. package/cli/app/.next-cli-build/server/app/dashboard/quota.html +2 -2
  227. package/cli/app/.next-cli-build/server/app/dashboard/quota.rsc +6 -6
  228. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
  229. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
  230. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  231. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  232. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
  233. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
  234. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
  235. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
  236. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  237. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
  238. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +3 -3
  239. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
  240. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
  241. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
  242. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
  243. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
  244. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
  245. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
  246. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
  247. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.html +1 -1
  248. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.rsc +5 -5
  249. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +2 -2
  250. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver.segment.rsc +1 -1
  251. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  252. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  253. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +5 -5
  254. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_head.segment.rsc +1 -1
  255. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_index.segment.rsc +3 -3
  256. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
  257. package/cli/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
  258. package/cli/app/.next-cli-build/server/app/dashboard/translator.rsc +5 -5
  259. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
  260. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
  261. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  262. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  263. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
  264. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
  265. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
  266. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
  267. package/cli/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
  268. package/cli/app/.next-cli-build/server/app/dashboard/usage.rsc +5 -5
  269. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
  270. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
  271. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  272. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  273. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
  274. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
  275. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
  276. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
  277. package/cli/app/.next-cli-build/server/app/dashboard.html +1 -1
  278. package/cli/app/.next-cli-build/server/app/dashboard.rsc +5 -5
  279. package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
  280. package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  281. package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  282. package/cli/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +5 -5
  283. package/cli/app/.next-cli-build/server/app/dashboard.segments/_head.segment.rsc +1 -1
  284. package/cli/app/.next-cli-build/server/app/dashboard.segments/_index.segment.rsc +3 -3
  285. package/cli/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +1 -1
  286. package/cli/app/.next-cli-build/server/app/index.html +1 -1
  287. package/cli/app/.next-cli-build/server/app/index.rsc +3 -3
  288. package/cli/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  289. package/cli/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +3 -3
  290. package/cli/app/.next-cli-build/server/app/index.segments/_head.segment.rsc +1 -1
  291. package/cli/app/.next-cli-build/server/app/index.segments/_index.segment.rsc +3 -3
  292. package/cli/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +1 -1
  293. package/cli/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
  294. package/cli/app/.next-cli-build/server/app/landing.html +1 -1
  295. package/cli/app/.next-cli-build/server/app/landing.rsc +3 -3
  296. package/cli/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +3 -3
  297. package/cli/app/.next-cli-build/server/app/landing.segments/_head.segment.rsc +1 -1
  298. package/cli/app/.next-cli-build/server/app/landing.segments/_index.segment.rsc +3 -3
  299. package/cli/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +1 -1
  300. package/cli/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
  301. package/cli/app/.next-cli-build/server/app/landing.segments/landing.segment.rsc +1 -1
  302. package/cli/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
  303. package/cli/app/.next-cli-build/server/app/login.html +1 -1
  304. package/cli/app/.next-cli-build/server/app/login.rsc +4 -4
  305. package/cli/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +4 -4
  306. package/cli/app/.next-cli-build/server/app/login.segments/_head.segment.rsc +1 -1
  307. package/cli/app/.next-cli-build/server/app/login.segments/_index.segment.rsc +3 -3
  308. package/cli/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +1 -1
  309. package/cli/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  310. package/cli/app/.next-cli-build/server/app/login.segments/login.segment.rsc +1 -1
  311. package/cli/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
  312. package/cli/app/.next-cli-build/server/app-paths-manifest.json +9 -9
  313. package/cli/app/.next-cli-build/server/chunks/3110.js +2 -2
  314. package/cli/app/.next-cli-build/server/chunks/3155.js +1 -1
  315. package/cli/app/.next-cli-build/server/chunks/318.js +8 -8
  316. package/cli/app/.next-cli-build/server/chunks/3407.js +1 -1
  317. package/cli/app/.next-cli-build/server/chunks/4632.js +1 -1
  318. package/cli/app/.next-cli-build/server/chunks/4746.js +1 -1
  319. package/cli/app/.next-cli-build/server/chunks/6896.js +1 -1
  320. package/cli/app/.next-cli-build/server/chunks/8157.js +1 -1
  321. package/cli/app/.next-cli-build/server/chunks/8895.js +1 -1
  322. package/cli/app/.next-cli-build/server/chunks/9489.js +1 -1
  323. package/cli/app/.next-cli-build/server/chunks/9609.js +1 -1
  324. package/cli/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
  325. package/cli/app/.next-cli-build/server/pages/404.html +1 -1
  326. package/cli/app/.next-cli-build/server/pages/500.html +1 -1
  327. package/cli/app/.next-cli-build/static/chunks/{3702-2a500d2721737415.js → 3702-5dff3b2add59cd88.js} +1 -1
  328. package/cli/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/cli-tools/page-c99774d53ed03829.js +1 -0
  329. package/cli/app/.openclaude/worktrees/agent-a785ba58/src/lib/terminal/ptyBridge.py +163 -0
  330. package/cli/app/package.json +1 -1
  331. package/cli/package.json +1 -1
  332. package/open-sse/config/errorConfig.js +2 -0
  333. package/open-sse/executors/base.js +36 -1
  334. package/open-sse/services/accountFallback.js +6 -1
  335. package/open-sse/services/combo.js +1 -10
  336. package/package.json +1 -1
  337. package/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.js +25 -14
  338. package/src/app/(dashboard)/dashboard/cli-tools/components/ToolSummaryCard.js +1 -0
  339. package/src/app/api/cli-tools/all-statuses/route.js +2 -2
  340. package/src/app/api/v1/messages/count_tokens/route.js +20 -13
  341. package/src/app/api/v1beta/models/[...path]/route.js +98 -58
  342. package/src/lib/oauth/services/kiroBulkImportManager.js +11 -0
  343. package/src/sse/handlers/embeddings.js +1 -1
  344. package/cli/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/cli-tools/page-af6c0246d5d96fd4.js +0 -1
  345. /package/cli/app/.next-cli-build/static/{SridO8vAj0YEv4XGDh26_ → 9thlCEOM7BraCgtlZNTC_}/_buildManifest.js +0 -0
  346. /package/cli/app/.next-cli-build/static/{SridO8vAj0YEv4XGDh26_ → 9thlCEOM7BraCgtlZNTC_}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2326],{53501:(e,s,l)=>{"use strict";l.d(s,{default:()=>m});var t=l(95155),a=l(12115),r=l(35497),i=l(3534),n=l(43666),o=l(98500),c=l.n(o),d=l(5772);function x({toolId:e,tool:s,status:l}){let a=l?.error?{label:"Unavailable",cls:"bg-red-500/10 text-red-600 dark:text-red-400"}:l?l.installed?l.hasZevai?{label:"Connected",cls:"bg-green-500/10 text-green-600 dark:text-green-400"}:{label:"Not configured",cls:"bg-yellow-500/10 text-yellow-600 dark:text-yellow-400"}:{label:"Not installed",cls:"bg-gray-500/10 text-gray-500"}:{label:"Unknown",cls:"bg-gray-500/10 text-gray-500"};return(0,t.jsx)(c(),{href:`/dashboard/cli-tools/${e}`,className:"block",children:(0,t.jsx)(r.Zp,{padding:"sm",className:"h-full overflow-hidden hover:border-primary/50 transition-colors cursor-pointer",children:(0,t.jsx)("div",{className:"flex h-full flex-col gap-2",children:(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("div",{className:"size-8 flex items-center justify-center shrink-0",children:s.image?(0,t.jsx)(d.default,{src:s.image,alt:s.name,width:32,height:32,className:"size-8 object-contain rounded-lg",sizes:"32px",onError:e=>{e.target.style.display="none"}}):s.icon?(0,t.jsx)("span",{className:"material-symbols-outlined text-[28px]",style:{color:s.color},children:s.icon}):null}),(0,t.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,t.jsx)("h3",{className:"font-medium text-sm truncate",children:s.name}),(0,t.jsx)("span",{className:`inline-block mt-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full ${a.cls}`,children:a.label})]}),(0,t.jsx)("span",{className:"material-symbols-outlined text-text-muted text-[18px] shrink-0",children:"chevron_right"})]})})})})}function m({machineId:e}){let[s,l]=(0,a.useState)(!0),[o,c]=(0,a.useState)({}),d=(0,a.useCallback)(async e=>{try{let s=await fetch("/api/cli-tools/all-statuses",{signal:e});s.ok&&c(await s.json())}catch(e){"AbortError"!==e.name&&console.log("Error fetching tool statuses:",e)}finally{e.aborted||l(!1)}},[]);if((0,a.useEffect)(()=>{let e=new AbortController;d(e.signal);let s=()=>{e.abort(),d((e=new AbortController).signal)};return window.addEventListener("focus",s),()=>{e.abort(),window.removeEventListener("focus",s)}},[d]),s)return(0,t.jsxs)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4",children:[(0,t.jsx)(r.Qv,{}),(0,t.jsx)(r.Qv,{}),(0,t.jsx)(r.Qv,{}),(0,t.jsx)(r.Qv,{}),(0,t.jsx)(r.Qv,{}),(0,t.jsx)(r.Qv,{})]});let g=Object.entries(i.dM),h=Object.entries(i.wn);return(0,t.jsxs)("div",{className:"mx-auto flex w-full max-w-5xl flex-col gap-6 px-1 sm:px-0",children:[(0,t.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4",children:g.map(([e,s])=>(0,t.jsx)(x,{toolId:e,tool:s,status:o[e]},e))}),(0,t.jsxs)("div",{className:"flex flex-col gap-3 sm:gap-4",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2 px-1",children:[(0,t.jsx)("span",{className:"material-symbols-outlined text-[18px] text-primary",children:"security"}),(0,t.jsx)("h2",{className:"text-sm font-semibold text-text-main",children:"MITM Tools"})]}),(0,t.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4",children:h.map(([e,s])=>(0,t.jsx)(n.gY,{tool:s},e))})]})]})}},89734:(e,s,l)=>{Promise.resolve().then(l.bind(l,53501))}},e=>{e.O(0,[2574,3862,4343,3702,5497,6069,8441,3794,7358],()=>e(e.s=89734)),_N_E=e.O()}]);
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Minimal PTY bridge for ZevaiRouter web terminal.
4
+
5
+ stdin -> PTY master (keystrokes)
6
+ stdout <- PTY master (shell output), raw binary
7
+ stderr = control / errors (utf-8 text lines)
8
+
9
+ Optional control on a side channel is not needed: resize arrives as
10
+ OSC-like escape on stdin: \\x1b]9999;<cols>;<rows>\\x07
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import errno
15
+ import fcntl
16
+ import os
17
+ import select
18
+ import signal
19
+ import struct
20
+ import sys
21
+ import termios
22
+
23
+
24
+ def set_winsize(fd: int, rows: int, cols: int) -> None:
25
+ try:
26
+ packed = struct.pack("HHHH", max(5, rows), max(20, cols), 0, 0)
27
+ fcntl.ioctl(fd, termios.TIOCSWINSZ, packed)
28
+ except Exception:
29
+ pass
30
+
31
+
32
+ def main() -> int:
33
+ cols = int(sys.argv[1]) if len(sys.argv) > 1 else 120
34
+ rows = int(sys.argv[2]) if len(sys.argv) > 2 else 40
35
+ shell = os.environ.get("SHELL") or ("/bin/bash" if os.path.exists("/bin/bash") else "/bin/sh")
36
+ cwd = os.path.expanduser("~")
37
+
38
+ pid, master = pty_fork = _fork_pty()
39
+ if pid == 0:
40
+ # child
41
+ try:
42
+ os.chdir(cwd)
43
+ except Exception:
44
+ pass
45
+ os.environ.setdefault("TERM", "xterm-256color")
46
+ os.environ.setdefault("COLORTERM", "truecolor")
47
+ os.environ.setdefault("FORCE_COLOR", "1")
48
+ try:
49
+ os.execv(shell, [shell, "-il"])
50
+ except Exception:
51
+ os.execv("/bin/sh", ["/bin/sh", "-i"])
52
+ return 1
53
+
54
+ set_winsize(master, rows, cols)
55
+
56
+ # Non-blocking master + stdin
57
+ for fd in (master, sys.stdin.fileno()):
58
+ fl = fcntl.fcntl(fd, fcntl.F_GETFL)
59
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
60
+
61
+ # Binary stdout
62
+ stdout = sys.stdout.buffer
63
+ stdin = sys.stdin.buffer
64
+
65
+ resize_buf = b""
66
+
67
+ def handle_resize_escape(chunk: bytes) -> bytes:
68
+ """Strip and apply embedded resize escapes, return remaining bytes."""
69
+ nonlocal resize_buf
70
+ data = resize_buf + chunk
71
+ out = bytearray()
72
+ i = 0
73
+ while i < len(data):
74
+ # ESC ] 9999 ; cols ; rows BEL
75
+ if data[i] == 0x1B and data[i : i + 6] == b"\x1b]9999;":
76
+ end = data.find(b"\x07", i + 6)
77
+ if end < 0:
78
+ resize_buf = data[i:]
79
+ return bytes(out)
80
+ payload = data[i + 6 : end].decode("ascii", "ignore")
81
+ try:
82
+ c_s, r_s = payload.split(";", 1)
83
+ set_winsize(master, int(r_s), int(c_s))
84
+ except Exception:
85
+ pass
86
+ i = end + 1
87
+ resize_buf = b""
88
+ continue
89
+ out.append(data[i])
90
+ i += 1
91
+ resize_buf = b""
92
+ return bytes(out)
93
+
94
+ alive = True
95
+
96
+ def on_chld(signum, frame): # noqa: ARG001
97
+ nonlocal alive
98
+ alive = False
99
+
100
+ signal.signal(signal.SIGCHLD, on_chld)
101
+
102
+ try:
103
+ while alive:
104
+ try:
105
+ r, _, _ = select.select([master, sys.stdin.fileno()], [], [], 0.25)
106
+ except InterruptedError:
107
+ continue
108
+
109
+ if master in r:
110
+ try:
111
+ data = os.read(master, 8192)
112
+ except OSError as e:
113
+ if e.errno in (errno.EIO, errno.EAGAIN, errno.EWOULDBLOCK):
114
+ data = b""
115
+ else:
116
+ break
117
+ if not data:
118
+ # EIO often means child exited
119
+ if not alive:
120
+ break
121
+ else:
122
+ stdout.write(data)
123
+ stdout.flush()
124
+
125
+ if sys.stdin.fileno() in r:
126
+ try:
127
+ data = stdin.read(8192)
128
+ except Exception:
129
+ data = b""
130
+ if data is None:
131
+ data = b""
132
+ if data == b"" and not alive:
133
+ break
134
+ if data:
135
+ cleaned = handle_resize_escape(data)
136
+ if cleaned:
137
+ try:
138
+ os.write(master, cleaned)
139
+ except OSError:
140
+ break
141
+ finally:
142
+ try:
143
+ os.close(master)
144
+ except Exception:
145
+ pass
146
+ try:
147
+ os.waitpid(pid, 0)
148
+ except Exception:
149
+ pass
150
+ return 0
151
+
152
+
153
+ def _fork_pty():
154
+ import pty
155
+
156
+ return pty.fork()
157
+
158
+
159
+ if __name__ == "__main__":
160
+ try:
161
+ raise SystemExit(main())
162
+ except KeyboardInterrupt:
163
+ raise SystemExit(0)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zevairouter",
3
- "version": "1.0.116",
3
+ "version": "1.0.118",
4
4
  "description": "Self-hosted AI router: many providers, one OpenAI-compatible /v1 endpoint and dashboard",
5
5
  "bin": {
6
6
  "zevai": "./cli/cli.js"
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zevairouter-cli",
3
- "version": "1.0.116",
3
+ "version": "1.0.118",
4
4
  "description": "ZevaiRouter CLI - Start and manage ZevaiRouter server",
5
5
  "bin": {
6
6
  "zevai": "./cli.js"
@@ -77,6 +77,8 @@ export const ERROR_RULES = [
77
77
  { status: 402, cooldownMs: COOLDOWN.long },
78
78
  { status: 403, cooldownMs: COOLDOWN.long },
79
79
  { status: 404, cooldownMs: COOLDOWN.long },
80
+ { status: 408, cooldownMs: COOLDOWN.short },
81
+ { status: 409, cooldownMs: COOLDOWN.short },
80
82
  { status: 429, backoff: true },
81
83
  ];
82
84
 
@@ -4,6 +4,41 @@ import { shouldRefreshCredentials } from "../services/oauthCredentialManager.js"
4
4
  import { proxyAwareFetch } from "../utils/proxyFetch.js";
5
5
  import { dbg } from "../utils/debugLog.js";
6
6
 
7
+ export function withBodyTimeout(response, timeoutMs, abortController, signal) {
8
+ if (!response.body || !timeoutMs) return response;
9
+ const reader = response.body.getReader();
10
+ const body = new ReadableStream({
11
+ async pull(controller) {
12
+ if (signal?.aborted) throw signal.reason;
13
+ let timer;
14
+ try {
15
+ const timeout = new Promise((_, reject) => {
16
+ timer = setTimeout(() => {
17
+ const error = new Error("response body timeout");
18
+ reject(error);
19
+ queueMicrotask(() => {
20
+ abortController.abort(error);
21
+ reader.cancel(error).catch(() => {});
22
+ });
23
+ }, timeoutMs);
24
+ });
25
+ const { done, value } = await Promise.race([reader.read(), timeout]);
26
+ if (signal?.aborted) throw signal.reason;
27
+ if (done) controller.close();
28
+ else controller.enqueue(value);
29
+ } catch (error) {
30
+ controller.error(error);
31
+ } finally {
32
+ clearTimeout(timer);
33
+ }
34
+ },
35
+ cancel(reason) {
36
+ return reader.cancel(reason);
37
+ },
38
+ });
39
+ return new Response(body, response);
40
+ }
41
+
7
42
  /**
8
43
  * BaseExecutor - Base class for provider executors
9
44
  */
@@ -159,7 +194,7 @@ export class BaseExecutor {
159
194
  continue;
160
195
  }
161
196
 
162
- return { response, url, headers, transformedBody };
197
+ return { response: withBodyTimeout(response, this.config?.responseTimeoutMs || timeoutMs, connectCtrl, signal), url, headers, transformedBody };
163
198
  } catch (error) {
164
199
  clearTimeout(connectTimer);
165
200
  lastError = error;
@@ -68,7 +68,12 @@ export function checkFallbackError(status, errorText, backoffLevel = 0) {
68
68
  }
69
69
  }
70
70
 
71
- // Default: transient cooldown for any unmatched error
71
+ // Unmatched request-caused client errors belong to the request, not the account.
72
+ if (status >= 400 && status < 500) {
73
+ return { shouldFallback: false, cooldownMs: 0 };
74
+ }
75
+
76
+ // Default: transient cooldown for unknown server/network errors
72
77
  return { shouldFallback: true, cooldownMs: TRANSIENT_COOLDOWN_MS };
73
78
  }
74
79
 
@@ -148,22 +148,13 @@ export async function handleComboChat({ body, models, handleSingleModel, log, co
148
148
  }
149
149
 
150
150
  // Check if should fallback to next model
151
- const { shouldFallback, cooldownMs } = checkFallbackError(result.status, errorText);
151
+ const { shouldFallback } = checkFallbackError(result.status, errorText);
152
152
 
153
153
  if (!shouldFallback) {
154
154
  log.warn("COMBO", `Model ${modelStr} failed (no fallback)`, { status: result.status });
155
155
  return result;
156
156
  }
157
157
 
158
- // For transient errors (503/502/504), wait for cooldown before falling through
159
- // so a briefly-overloaded provider gets a chance to recover rather than being
160
- // skipped immediately (fixes: combo falls through on transient 503)
161
- if (cooldownMs && cooldownMs > 0 && cooldownMs <= 5000 &&
162
- (result.status === 503 || result.status === 502 || result.status === 504)) {
163
- log.info("COMBO", `Model ${modelStr} transient ${result.status}, waiting ${cooldownMs}ms before next`);
164
- await new Promise(r => setTimeout(r, cooldownMs));
165
- }
166
-
167
158
  // Fallback to next model
168
159
  lastError = errorText || String(result.status);
169
160
  if (!lastStatus) lastStatus = result.status;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zevairouter",
3
- "version": "1.0.116",
3
+ "version": "1.0.118",
4
4
  "description": "Self-hosted AI router: many providers, one OpenAI-compatible /v1 endpoint and dashboard",
5
5
  "bin": {
6
6
  "zevai": "./cli/cli.js"
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useState, useEffect } from "react";
3
+ import { useState, useEffect, useCallback } from "react";
4
4
  import { CardSkeleton } from "@/shared/components";
5
5
  import { CLI_TOOLS, MITM_TOOLS } from "@/shared/constants/cliTools";
6
6
  import { MitmLinkCard } from "./components";
@@ -12,21 +12,32 @@ export default function CLIToolsPageClient({ machineId }) {
12
12
  const [loading, setLoading] = useState(true);
13
13
  const [toolStatuses, setToolStatuses] = useState({});
14
14
 
15
- useEffect(() => {
16
- let mounted = true;
17
- (async () => {
18
- try {
19
- const res = await fetch(ALL_STATUSES_URL);
20
- if (res.ok && mounted) setToolStatuses(await res.json());
21
- } catch (error) {
22
- console.log("Error fetching tool statuses:", error);
23
- } finally {
24
- if (mounted) setLoading(false);
25
- }
26
- })();
27
- return () => { mounted = false; };
15
+ const fetchStatuses = useCallback(async (signal) => {
16
+ try {
17
+ const res = await fetch(ALL_STATUSES_URL, { signal });
18
+ if (res.ok) setToolStatuses(await res.json());
19
+ } catch (error) {
20
+ if (error.name !== "AbortError") console.log("Error fetching tool statuses:", error);
21
+ } finally {
22
+ if (!signal.aborted) setLoading(false);
23
+ }
28
24
  }, []);
29
25
 
26
+ useEffect(() => {
27
+ let controller = new AbortController();
28
+ fetchStatuses(controller.signal);
29
+ const onFocus = () => {
30
+ controller.abort();
31
+ controller = new AbortController();
32
+ fetchStatuses(controller.signal);
33
+ };
34
+ window.addEventListener("focus", onFocus);
35
+ return () => {
36
+ controller.abort();
37
+ window.removeEventListener("focus", onFocus);
38
+ };
39
+ }, [fetchStatuses]);
40
+
30
41
  if (loading) {
31
42
  return (
32
43
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
@@ -6,6 +6,7 @@ import { Card } from "@/shared/components";
6
6
 
7
7
  // Derive simple connected/configured/not-installed status from API payload
8
8
  function getStatus(status) {
9
+ if (status?.error) return { label: "Unavailable", cls: "bg-red-500/10 text-red-600 dark:text-red-400" };
9
10
  if (!status) return { label: "Unknown", cls: "bg-gray-500/10 text-gray-500" };
10
11
  if (!status.installed) return { label: "Not installed", cls: "bg-gray-500/10 text-gray-500" };
11
12
  if (status.hasZevai) return { label: "Connected", cls: "bg-green-500/10 text-green-600 dark:text-green-400" };
@@ -37,8 +37,8 @@ export async function GET() {
37
37
  const res = await getter();
38
38
  const data = await res.json();
39
39
  return [toolId, data];
40
- } catch {
41
- return [toolId, null];
40
+ } catch (error) {
41
+ return [toolId, { error: error instanceof Error ? error.message : "Status unavailable" }];
42
42
  }
43
43
  })
44
44
  );
@@ -25,21 +25,28 @@ export async function POST(request) {
25
25
  });
26
26
  }
27
27
 
28
- // Estimate token count based on content length
29
- const messages = body.messages || [];
30
- let totalChars = 0;
31
- for (const msg of messages) {
32
- if (typeof msg.content === "string") {
33
- totalChars += msg.content.length;
34
- } else if (Array.isArray(msg.content)) {
35
- for (const part of msg.content) {
36
- if (part.type === "text" && part.text) {
37
- totalChars += part.text.length;
38
- }
39
- }
40
- }
28
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
29
+ return new Response(JSON.stringify({ error: "Invalid request body" }), {
30
+ status: 400,
31
+ headers: { "Content-Type": "application/json", ...CORS_HEADERS }
32
+ });
41
33
  }
42
34
 
35
+ const textOf = (value) => {
36
+ if (typeof value === "string") return value;
37
+ if (value == null) return "";
38
+ if (Array.isArray(value)) return value.map(textOf).join(" ");
39
+ if (typeof value === "object") {
40
+ if (typeof value.text === "string") return value.text;
41
+ if (typeof value.content === "string") return value.content;
42
+ return JSON.stringify(value);
43
+ }
44
+ return String(value);
45
+ };
46
+
47
+ let totalChars = textOf(body.system).length + textOf(body.tools).length;
48
+ for (const msg of body.messages || []) totalChars += textOf(msg).length;
49
+
43
50
  // Rough estimate: ~4 chars per token
44
51
  const inputTokens = Math.ceil(totalChars / 4);
45
52
 
@@ -43,39 +43,24 @@ export async function POST(request, { params }) {
43
43
 
44
44
  try {
45
45
  const { path } = await params;
46
- // path = ["provider", "model:action"] or ["model:action"]
47
-
48
- let model;
49
- let action; // ":generateContent" | ":streamGenerateContent"
50
-
51
- if (path.length >= 2) {
52
- // Format: /v1beta/models/provider/model:generateContent
53
- const provider = path[0];
54
- const modelAction = path[1];
55
- action = modelAction.includes(":streamGenerateContent")
56
- ? ":streamGenerateContent"
57
- : ":generateContent";
58
- const modelName = modelAction
59
- .replace(":streamGenerateContent", "")
60
- .replace(":generateContent", "");
61
- model = provider + "/" + modelName;
62
- } else {
63
- // Format: /v1beta/models/model:generateContent
64
- const modelAction = path[0];
65
- action = modelAction.includes(":streamGenerateContent")
66
- ? ":streamGenerateContent"
67
- : ":generateContent";
68
- model = modelAction
69
- .replace(":streamGenerateContent", "")
70
- .replace(":generateContent", "");
46
+ if (!Array.isArray(path) || path.length < 1 || path.length > 2) {
47
+ return Response.json({ error: { message: "Invalid model path", code: 400 } }, { status: 400 });
48
+ }
49
+
50
+ const modelAction = path.at(-1);
51
+ const match = /^([^:]+):(generateContent|streamGenerateContent)$/.exec(modelAction);
52
+ if (!match || (path.length === 2 && (!path[0] || path[0].includes(":")))) {
53
+ return Response.json({ error: { message: "Invalid model action", code: 400 } }, { status: 400 });
71
54
  }
55
+ const model = path.length === 2 ? `${path[0]}/${match[1]}` : match[1];
56
+ const action = match[2];
72
57
 
73
58
  const body = await request.json();
74
59
 
75
60
  // Streaming is determined by URL action suffix:
76
61
  // :streamGenerateContent => stream: true (SSE)
77
62
  // :generateContent => stream: false (plain JSON)
78
- const stream = action === ":streamGenerateContent";
63
+ const stream = action === "streamGenerateContent";
79
64
 
80
65
  // Convert Gemini request format to OpenAI/internal format
81
66
  const convertedBody = convertGeminiToInternal(body, model, stream);
@@ -100,9 +85,10 @@ export async function POST(request, { params }) {
100
85
  }
101
86
  } catch (error) {
102
87
  console.log("Error handling Gemini request:", error);
88
+ const status = error.status || (error instanceof SyntaxError ? 400 : 500);
103
89
  return Response.json(
104
- { error: { message: error.message, code: 500 } },
105
- { status: 500 }
90
+ { error: { message: error.message, code: status } },
91
+ { status }
106
92
  );
107
93
  }
108
94
  }
@@ -114,38 +100,86 @@ export async function POST(request, { params }) {
114
100
  * @param {string} model - resolved model string (e.g. "gemini-pro-high")
115
101
  * @param {boolean} stream - whether to stream (from URL action)
116
102
  */
117
- function convertGeminiToInternal(geminiBody, model, stream) {
103
+ export function convertGeminiToInternal(geminiBody, model, stream) {
118
104
  const messages = [];
105
+ const allowedTopLevel = new Set(["contents", "systemInstruction", "generationConfig", "tools", "toolConfig", "safetySettings", "cachedContent"]);
106
+ const unsupported = Object.keys(geminiBody).filter(key => !allowedTopLevel.has(key));
107
+ if (unsupported.length || geminiBody.toolConfig || geminiBody.safetySettings || geminiBody.cachedContent) {
108
+ throw new ClientError(`Unsupported Gemini options: ${unsupported.concat([geminiBody.toolConfig && "toolConfig", geminiBody.safetySettings && "safetySettings", geminiBody.cachedContent && "cachedContent"].filter(Boolean)).join(", ")}`);
109
+ }
119
110
 
120
- // Convert system instruction
121
- if (geminiBody.systemInstruction) {
122
- const systemText = geminiBody.systemInstruction.parts
123
- ?.map(p => p.text)
124
- .join("\n") || "";
125
- if (systemText) {
126
- messages.push({ role: "system", content: systemText });
111
+ const mapParts = (parts = []) => parts.map(part => {
112
+ if (typeof part.text === "string") return { type: "text", text: part.text };
113
+ if (part.inlineData?.mimeType && part.inlineData?.data) {
114
+ return { type: "image_url", image_url: { url: `data:${part.inlineData.mimeType};base64,${part.inlineData.data}` } };
115
+ }
116
+ if (part.functionCall?.name) {
117
+ return { type: "tool_call", id: part.functionCall.id, function: { name: part.functionCall.name, arguments: JSON.stringify(part.functionCall.args || {}) } };
118
+ }
119
+ if (part.functionResponse?.name) {
120
+ return { type: "tool_result", tool_call_id: part.functionResponse.id || part.functionResponse.name, content: JSON.stringify(part.functionResponse.response ?? {}) };
127
121
  }
122
+ throw new ClientError(`Unsupported Gemini content part: ${Object.keys(part).join(", ") || "empty part"}`);
123
+ });
124
+
125
+ if (geminiBody.systemInstruction) {
126
+ const parts = mapParts(geminiBody.systemInstruction.parts);
127
+ if (parts.some(part => part.type !== "text")) throw new ClientError("System instruction only supports text parts");
128
+ messages.push({ role: "system", content: parts.map(part => part.text).join("\n") });
128
129
  }
129
130
 
130
- // Convert contents to messages
131
- if (geminiBody.contents) {
132
- for (const content of geminiBody.contents) {
133
- const role = content.role === "model" ? "assistant" : "user";
134
- const text = content.parts?.map(p => p.text).join("\n") || "";
135
- messages.push({ role, content: text });
131
+ for (const content of geminiBody.contents || []) {
132
+ if (!content || !["user", "model", "function"].includes(content.role) || !Array.isArray(content.parts)) {
133
+ throw new ClientError("Invalid Gemini content");
134
+ }
135
+ const parts = mapParts(content.parts);
136
+ const role = content.role === "model" ? "assistant" : content.role === "function" ? "tool" : "user";
137
+ const textAndImages = parts.filter(part => part.type === "text" || part.type === "image_url");
138
+ const toolCalls = parts.filter(part => part.type === "tool_call");
139
+ const toolResults = parts.filter(part => part.type === "tool_result");
140
+ if (toolResults.length) {
141
+ for (const result of toolResults) messages.push({ role: "tool", tool_call_id: result.tool_call_id, content: result.content });
142
+ } else {
143
+ messages.push({
144
+ role,
145
+ content: textAndImages.length === 1 && textAndImages[0].type === "text" ? textAndImages[0].text : textAndImages,
146
+ ...(toolCalls.length ? { tool_calls: toolCalls.map(({ id, function: fn }, index) => ({ id: id || `call_${index}`, type: "function", function: fn })) } : {}),
147
+ });
136
148
  }
137
149
  }
138
150
 
151
+ const generationConfig = geminiBody.generationConfig || {};
152
+ const allowedGeneration = new Set(["maxOutputTokens", "temperature", "topP", "stopSequences", "responseMimeType", "responseSchema"]);
153
+ const unsupportedGeneration = Object.keys(generationConfig).filter(key => !allowedGeneration.has(key));
154
+ if (unsupportedGeneration.length) throw new ClientError(`Unsupported generation options: ${unsupportedGeneration.join(", ")}`);
155
+
156
+ const tools = (geminiBody.tools || []).flatMap(tool => {
157
+ if (!Array.isArray(tool.functionDeclarations) || Object.keys(tool).some(key => key !== "functionDeclarations")) {
158
+ throw new ClientError("Only Gemini function declarations are supported");
159
+ }
160
+ return tool.functionDeclarations.map(fn => ({ type: "function", function: { name: fn.name, description: fn.description, parameters: fn.parameters } }));
161
+ });
162
+
139
163
  return {
140
164
  model,
141
165
  messages,
142
166
  stream,
143
- max_tokens: geminiBody.generationConfig?.maxOutputTokens,
144
- temperature: geminiBody.generationConfig?.temperature,
145
- top_p: geminiBody.generationConfig?.topP,
167
+ max_tokens: generationConfig.maxOutputTokens,
168
+ temperature: generationConfig.temperature,
169
+ top_p: generationConfig.topP,
170
+ stop: generationConfig.stopSequences,
171
+ ...(tools.length ? { tools } : {}),
172
+ ...(generationConfig.responseMimeType === "application/json" ? { response_format: generationConfig.responseSchema ? { type: "json_schema", json_schema: { name: "response", schema: generationConfig.responseSchema } } : { type: "json_object" } } : {}),
146
173
  };
147
174
  }
148
175
 
176
+ class ClientError extends Error {
177
+ constructor(message) {
178
+ super(message);
179
+ this.status = 400;
180
+ }
181
+ }
182
+
149
183
  /** Map OpenAI finish_reason => Gemini finishReason */
150
184
  const FINISH_REASON_MAP = {
151
185
  stop: "STOP",
@@ -167,7 +201,7 @@ const FINISH_REASON_MAP = {
167
201
  * data: {"candidates":[{"content":{"role":"model","parts":[{"text":""}]},"finishReason":"STOP","index":0}],"usageMetadata":{...}}
168
202
  * (stream closes — no [DONE])
169
203
  */
170
- function transformOpenAISSEToGeminiSSE(upstreamResponse, model) {
204
+ export function transformOpenAISSEToGeminiSSE(upstreamResponse, model) {
171
205
  if (!upstreamResponse.ok || !upstreamResponse.body) {
172
206
  return upstreamResponse;
173
207
  }
@@ -175,29 +209,38 @@ function transformOpenAISSEToGeminiSSE(upstreamResponse, model) {
175
209
  const decoder = new TextDecoder();
176
210
  const encoder = new TextEncoder();
177
211
 
212
+ let buffer = "";
178
213
  const transformStream = new TransformStream({
179
214
  transform(chunk, controller) {
180
- const text = decoder.decode(chunk, { stream: true });
181
- const lines = text.split("\n");
215
+ buffer += decoder.decode(chunk, { stream: true });
216
+ const lines = buffer.split("\n");
217
+ buffer = lines.pop() || "";
218
+ for (const line of lines) emitLine(line, controller);
219
+ },
220
+ flush(controller) {
221
+ buffer += decoder.decode();
222
+ if (buffer) emitLine(buffer, controller);
223
+ },
224
+ });
182
225
 
183
- for (const line of lines) {
184
- if (!line.startsWith("data:")) continue;
226
+ function emitLine(line, controller) {
227
+ if (!line.startsWith("data:")) return;
185
228
 
186
229
  const data = line.slice(5).trim();
187
230
 
188
231
  // Drop empty lines and the OpenAI [DONE] sentinel.
189
232
  // Gemini SSE ends by stream close, no sentinel needed.
190
- if (!data || data === "[DONE]") continue;
233
+ if (!data || data === "[DONE]") return;
191
234
 
192
235
  let parsed;
193
236
  try {
194
237
  parsed = JSON.parse(data);
195
238
  } catch {
196
- continue;
239
+ return;
197
240
  }
198
241
 
199
242
  const choice = parsed.choices?.[0];
200
- if (!choice) continue;
243
+ if (!choice) return;
201
244
 
202
245
  const delta = choice.delta || {};
203
246
 
@@ -210,7 +253,7 @@ function transformOpenAISSEToGeminiSSE(upstreamResponse, model) {
210
253
  }
211
254
 
212
255
  // Skip pure role-only deltas with no content and no finish signal
213
- if (parts.length === 0 && !choice.finish_reason) continue;
256
+ if (parts.length === 0 && !choice.finish_reason) return;
214
257
 
215
258
  const candidate = {
216
259
  content: {
@@ -244,10 +287,7 @@ function transformOpenAISSEToGeminiSSE(upstreamResponse, model) {
244
287
  controller.enqueue(
245
288
  encoder.encode("data: " + JSON.stringify(geminiChunk) + "\r\n\r\n")
246
289
  );
247
- }
248
- },
249
- // No flush() needed: Gemini SSE ends by stream close, not a sentinel
250
- });
290
+ }
251
291
 
252
292
  return new Response(upstreamResponse.body.pipeThrough(transformStream), {
253
293
  status: 200,