@seqyuan/annodex 0.1.12 → 0.1.13

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 (478) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-path-routes-manifest.json +39 -0
  3. package/.next/build-manifest.json +20 -0
  4. package/.next/diagnostics/build-diagnostics.json +6 -0
  5. package/.next/diagnostics/framework.json +1 -0
  6. package/.next/export-marker.json +6 -0
  7. package/.next/images-manifest.json +68 -0
  8. package/.next/next-minimal-server.js.nft.json +1 -0
  9. package/.next/next-server.js.nft.json +1 -0
  10. package/.next/package.json +1 -0
  11. package/.next/prerender-manifest.json +109 -0
  12. package/.next/react-loadable-manifest.json +2320 -0
  13. package/.next/required-server-files.js +343 -0
  14. package/.next/required-server-files.json +343 -0
  15. package/.next/routes-manifest.json +286 -0
  16. package/.next/server/app/_global-error/page.js +32 -0
  17. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  18. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
  19. package/.next/server/app/_global-error.html +1 -0
  20. package/.next/server/app/_global-error.meta +16 -0
  21. package/.next/server/app/_global-error.rsc +14 -0
  22. package/.next/server/app/_global-error.segments/_full.segment.rsc +14 -0
  23. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +5 -0
  24. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +5 -0
  25. package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
  26. package/.next/server/app/_global-error.segments/_index.segment.rsc +5 -0
  27. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  28. package/.next/server/app/_not-found/page.js +2 -0
  29. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  30. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  31. package/.next/server/app/_not-found.html +1 -0
  32. package/.next/server/app/_not-found.meta +16 -0
  33. package/.next/server/app/_not-found.rsc +18 -0
  34. package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -0
  35. package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
  36. package/.next/server/app/_not-found.segments/_index.segment.rsc +5 -0
  37. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  38. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
  39. package/.next/server/app/_not-found.segments/_tree.segment.rsc +4 -0
  40. package/.next/server/app/api/agent/[id]/events/route.js +3 -0
  41. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -0
  42. package/.next/server/app/api/agent/[id]/events/route_client-reference-manifest.js +1 -0
  43. package/.next/server/app/api/agent/[id]/route.js +1 -0
  44. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -0
  45. package/.next/server/app/api/agent/[id]/route_client-reference-manifest.js +1 -0
  46. package/.next/server/app/api/agent/new/route.js +1 -0
  47. package/.next/server/app/api/agent/new/route.js.nft.json +1 -0
  48. package/.next/server/app/api/agent/new/route_client-reference-manifest.js +1 -0
  49. package/.next/server/app/api/auth/all-providers/route.js +1 -0
  50. package/.next/server/app/api/auth/all-providers/route.js.nft.json +1 -0
  51. package/.next/server/app/api/auth/all-providers/route_client-reference-manifest.js +1 -0
  52. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -0
  53. package/.next/server/app/api/auth/api-key/[provider]/route.js.nft.json +1 -0
  54. package/.next/server/app/api/auth/api-key/[provider]/route_client-reference-manifest.js +1 -0
  55. package/.next/server/app/api/auth/login/[provider]/route.js +1 -0
  56. package/.next/server/app/api/auth/login/[provider]/route.js.nft.json +1 -0
  57. package/.next/server/app/api/auth/login/[provider]/route_client-reference-manifest.js +1 -0
  58. package/.next/server/app/api/auth/login/route.js +1 -0
  59. package/.next/server/app/api/auth/login/route.js.nft.json +1 -0
  60. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -0
  61. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -0
  62. package/.next/server/app/api/auth/logout/[provider]/route.js.nft.json +1 -0
  63. package/.next/server/app/api/auth/logout/[provider]/route_client-reference-manifest.js +1 -0
  64. package/.next/server/app/api/auth/providers/route.js +1 -0
  65. package/.next/server/app/api/auth/providers/route.js.nft.json +1 -0
  66. package/.next/server/app/api/auth/providers/route_client-reference-manifest.js +1 -0
  67. package/.next/server/app/api/auth/status/route.js +1 -0
  68. package/.next/server/app/api/auth/status/route.js.nft.json +1 -0
  69. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -0
  70. package/.next/server/app/api/default-cwd/route.js +1 -0
  71. package/.next/server/app/api/default-cwd/route.js.nft.json +1 -0
  72. package/.next/server/app/api/default-cwd/route_client-reference-manifest.js +1 -0
  73. package/.next/server/app/api/files/[...path]/route.js +4 -0
  74. package/.next/server/app/api/files/[...path]/route.js.nft.json +1 -0
  75. package/.next/server/app/api/files/[...path]/route_client-reference-manifest.js +1 -0
  76. package/.next/server/app/api/harness/route.js +1 -0
  77. package/.next/server/app/api/harness/route.js.nft.json +1 -0
  78. package/.next/server/app/api/harness/route_client-reference-manifest.js +1 -0
  79. package/.next/server/app/api/home/route.js +1 -0
  80. package/.next/server/app/api/home/route.js.nft.json +1 -0
  81. package/.next/server/app/api/home/route_client-reference-manifest.js +1 -0
  82. package/.next/server/app/api/internal/runtime/route.js +1 -0
  83. package/.next/server/app/api/internal/runtime/route.js.nft.json +1 -0
  84. package/.next/server/app/api/internal/runtime/route_client-reference-manifest.js +1 -0
  85. package/.next/server/app/api/models/route.js +1 -0
  86. package/.next/server/app/api/models/route.js.nft.json +1 -0
  87. package/.next/server/app/api/models/route_client-reference-manifest.js +1 -0
  88. package/.next/server/app/api/models-config/discover/route.js +1 -0
  89. package/.next/server/app/api/models-config/discover/route.js.nft.json +1 -0
  90. package/.next/server/app/api/models-config/discover/route_client-reference-manifest.js +1 -0
  91. package/.next/server/app/api/models-config/route.js +1 -0
  92. package/.next/server/app/api/models-config/route.js.nft.json +1 -0
  93. package/.next/server/app/api/models-config/route_client-reference-manifest.js +1 -0
  94. package/.next/server/app/api/models-config/test/route.js +1 -0
  95. package/.next/server/app/api/models-config/test/route.js.nft.json +1 -0
  96. package/.next/server/app/api/models-config/test/route_client-reference-manifest.js +1 -0
  97. package/.next/server/app/api/projects/browse/route.js +1 -0
  98. package/.next/server/app/api/projects/browse/route.js.nft.json +1 -0
  99. package/.next/server/app/api/projects/browse/route_client-reference-manifest.js +1 -0
  100. package/.next/server/app/api/projects/route.js +1 -0
  101. package/.next/server/app/api/projects/route.js.nft.json +1 -0
  102. package/.next/server/app/api/projects/route_client-reference-manifest.js +1 -0
  103. package/.next/server/app/api/reports/[id]/route.js +10 -0
  104. package/.next/server/app/api/reports/[id]/route.js.nft.json +1 -0
  105. package/.next/server/app/api/reports/[id]/route_client-reference-manifest.js +1 -0
  106. package/.next/server/app/api/search/route.js +1 -0
  107. package/.next/server/app/api/search/route.js.nft.json +1 -0
  108. package/.next/server/app/api/search/route_client-reference-manifest.js +1 -0
  109. package/.next/server/app/api/sessions/[id]/context/route.js +1 -0
  110. package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -0
  111. package/.next/server/app/api/sessions/[id]/context/route_client-reference-manifest.js +1 -0
  112. package/.next/server/app/api/sessions/[id]/route.js +1 -0
  113. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -0
  114. package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -0
  115. package/.next/server/app/api/sessions/new/route.js +1 -0
  116. package/.next/server/app/api/sessions/new/route.js.nft.json +1 -0
  117. package/.next/server/app/api/sessions/new/route_client-reference-manifest.js +1 -0
  118. package/.next/server/app/api/sessions/route.js +1 -0
  119. package/.next/server/app/api/sessions/route.js.nft.json +1 -0
  120. package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -0
  121. package/.next/server/app/api/settings/route.js +1 -0
  122. package/.next/server/app/api/settings/route.js.nft.json +1 -0
  123. package/.next/server/app/api/settings/route_client-reference-manifest.js +1 -0
  124. package/.next/server/app/api/skills/install/route.js +5 -0
  125. package/.next/server/app/api/skills/install/route.js.nft.json +1 -0
  126. package/.next/server/app/api/skills/install/route_client-reference-manifest.js +1 -0
  127. package/.next/server/app/api/skills/route.js +6 -0
  128. package/.next/server/app/api/skills/route.js.nft.json +1 -0
  129. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -0
  130. package/.next/server/app/api/skills/search/route.js +1 -0
  131. package/.next/server/app/api/skills/search/route.js.nft.json +1 -0
  132. package/.next/server/app/api/skills/search/route_client-reference-manifest.js +1 -0
  133. package/.next/server/app/api/soul/route.js +1 -0
  134. package/.next/server/app/api/soul/route.js.nft.json +1 -0
  135. package/.next/server/app/api/soul/route_client-reference-manifest.js +1 -0
  136. package/.next/server/app/api/version/route.js +1 -0
  137. package/.next/server/app/api/version/route.js.nft.json +1 -0
  138. package/.next/server/app/api/version/route_client-reference-manifest.js +1 -0
  139. package/.next/server/app/index.html +1 -0
  140. package/.next/server/app/index.meta +14 -0
  141. package/.next/server/app/index.rsc +17 -0
  142. package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -0
  143. package/.next/server/app/index.segments/_full.segment.rsc +17 -0
  144. package/.next/server/app/index.segments/_head.segment.rsc +6 -0
  145. package/.next/server/app/index.segments/_index.segment.rsc +5 -0
  146. package/.next/server/app/index.segments/_tree.segment.rsc +4 -0
  147. package/.next/server/app/login/page.js +2 -0
  148. package/.next/server/app/login/page.js.nft.json +1 -0
  149. package/.next/server/app/login/page_client-reference-manifest.js +1 -0
  150. package/.next/server/app/login.html +1 -0
  151. package/.next/server/app/login.meta +15 -0
  152. package/.next/server/app/login.rsc +22 -0
  153. package/.next/server/app/login.segments/_full.segment.rsc +22 -0
  154. package/.next/server/app/login.segments/_head.segment.rsc +6 -0
  155. package/.next/server/app/login.segments/_index.segment.rsc +5 -0
  156. package/.next/server/app/login.segments/_tree.segment.rsc +4 -0
  157. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +9 -0
  158. package/.next/server/app/login.segments/login.segment.rsc +5 -0
  159. package/.next/server/app/page.js +261 -0
  160. package/.next/server/app/page.js.nft.json +1 -0
  161. package/.next/server/app/page_client-reference-manifest.js +1 -0
  162. package/.next/server/app-paths-manifest.json +39 -0
  163. package/.next/server/chunks/1048.js +1 -0
  164. package/.next/server/chunks/1367.js +77 -0
  165. package/.next/server/chunks/1381.js +1 -0
  166. package/.next/server/chunks/165.js +1 -0
  167. package/.next/server/chunks/1681.js +215 -0
  168. package/.next/server/chunks/1688.js +45 -0
  169. package/.next/server/chunks/1703.js +79 -0
  170. package/.next/server/chunks/1712.js +43 -0
  171. package/.next/server/chunks/1813.js +1 -0
  172. package/.next/server/chunks/2325.js +80 -0
  173. package/.next/server/chunks/258.js +1 -0
  174. package/.next/server/chunks/2671.js +287 -0
  175. package/.next/server/chunks/2778.js +1 -0
  176. package/.next/server/chunks/2943.js +1 -0
  177. package/.next/server/chunks/3031.js +226 -0
  178. package/.next/server/chunks/3181.js +1 -0
  179. package/.next/server/chunks/3493.js +1 -0
  180. package/.next/server/chunks/3672.js +1 -0
  181. package/.next/server/chunks/3701.js +104 -0
  182. package/.next/server/chunks/4013.js +1 -0
  183. package/.next/server/chunks/402.js +2 -0
  184. package/.next/server/chunks/4035.js +80 -0
  185. package/.next/server/chunks/4248.js +153 -0
  186. package/.next/server/chunks/4367.js +1 -0
  187. package/.next/server/chunks/4406.js +141 -0
  188. package/.next/server/chunks/4741.js +18 -0
  189. package/.next/server/chunks/4768.js +1 -0
  190. package/.next/server/chunks/4858.js +148 -0
  191. package/.next/server/chunks/4980.js +1 -0
  192. package/.next/server/chunks/5155.js +5 -0
  193. package/.next/server/chunks/5293.js +166 -0
  194. package/.next/server/chunks/5399.js +8 -0
  195. package/.next/server/chunks/5409.js +1 -0
  196. package/.next/server/chunks/5797.js +93 -0
  197. package/.next/server/chunks/5851.js +36 -0
  198. package/.next/server/chunks/6206.js +1 -0
  199. package/.next/server/chunks/6296.js +1 -0
  200. package/.next/server/chunks/63.js +45 -0
  201. package/.next/server/chunks/6346.js +1 -0
  202. package/.next/server/chunks/6406.js +23 -0
  203. package/.next/server/chunks/642.js +1 -0
  204. package/.next/server/chunks/6429.js +50 -0
  205. package/.next/server/chunks/6729.js +64 -0
  206. package/.next/server/chunks/6907.js +115 -0
  207. package/.next/server/chunks/6980.js +1 -0
  208. package/.next/server/chunks/7073.js +24 -0
  209. package/.next/server/chunks/7233.js +24 -0
  210. package/.next/server/chunks/7307.js +1 -0
  211. package/.next/server/chunks/7362.js +9 -0
  212. package/.next/server/chunks/7567.js +29 -0
  213. package/.next/server/chunks/7765.js +1 -0
  214. package/.next/server/chunks/7890.js +1 -0
  215. package/.next/server/chunks/8065.js +1 -0
  216. package/.next/server/chunks/8238.js +34 -0
  217. package/.next/server/chunks/8276.js +1 -0
  218. package/.next/server/chunks/8336.js +1 -0
  219. package/.next/server/chunks/8477.js +3 -0
  220. package/.next/server/chunks/8490.js +1 -0
  221. package/.next/server/chunks/8916.js +1 -0
  222. package/.next/server/chunks/9280.js +252 -0
  223. package/.next/server/chunks/9315.js +1 -0
  224. package/.next/server/chunks/9537.js +90 -0
  225. package/.next/server/chunks/966.js +1 -0
  226. package/.next/server/chunks/9818.js +21 -0
  227. package/.next/server/chunks/static/media/pdf.worker.min.c476e1a0.mjs +6 -0
  228. package/.next/server/functions-config-manifest.json +16 -0
  229. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  230. package/.next/server/middleware-build-manifest.js +1 -0
  231. package/.next/server/middleware-manifest.json +6 -0
  232. package/.next/server/middleware-react-loadable-manifest.js +1 -0
  233. package/.next/server/middleware.js +18 -0
  234. package/.next/server/middleware.js.nft.json +1 -0
  235. package/.next/server/next-font-manifest.js +1 -0
  236. package/.next/server/next-font-manifest.json +1 -0
  237. package/.next/server/pages/404.html +1 -0
  238. package/.next/server/pages/500.html +1 -0
  239. package/.next/server/pages-manifest.json +4 -0
  240. package/.next/server/prefetch-hints.json +1 -0
  241. package/.next/server/server-reference-manifest.js +1 -0
  242. package/.next/server/server-reference-manifest.json +1 -0
  243. package/.next/server/webpack-runtime.js +1 -0
  244. package/.next/static/chunks/0b9a0da7.9075af772487e743.js +62 -0
  245. package/.next/static/chunks/1413.922d232de90c0c41.js +115 -0
  246. package/.next/static/chunks/1643.467a526a1f24f54d.js +24 -0
  247. package/.next/static/chunks/1852.5543122f11aa7fed.js +1 -0
  248. package/.next/static/chunks/1960.b1e26436d7a5f586.js +1 -0
  249. package/.next/static/chunks/2170a4aa.4213bb2183c9cdf9.js +1 -0
  250. package/.next/static/chunks/2274.6cd173f80a1405a2.js +21 -0
  251. package/.next/static/chunks/2419.347fdfe3c170854d.js +166 -0
  252. package/.next/static/chunks/2619.9aac8983f30c7c8a.js +1 -0
  253. package/.next/static/chunks/2623.d20fabd8e18197c6.js +287 -0
  254. package/.next/static/chunks/2729.f5365061a849d659.js +34 -0
  255. package/.next/static/chunks/2821.934bcf60fbdc28c6.js +1 -0
  256. package/.next/static/chunks/2918becc.abff2ece1de37bc1.js +153 -0
  257. package/.next/static/chunks/2947.114e51cb06d1c01a.js +23 -0
  258. package/.next/static/chunks/3079.4c511fa1144e3adf.js +79 -0
  259. package/.next/static/chunks/3274.208ca44844cd7d95.js +148 -0
  260. package/.next/static/chunks/3308.465a94263d04bfea.js +73 -0
  261. package/.next/static/chunks/3325.e4bfe1ca657f3b5b.js +80 -0
  262. package/.next/static/chunks/3506.2a7eaa08b9f55337.js +90 -0
  263. package/.next/static/chunks/363642f4-043c1475ab9af70e.js +1 -0
  264. package/.next/static/chunks/3794-123fdf632563f469.js +32 -0
  265. package/.next/static/chunks/3837.a755ccfe6f9c1c1c.js +5 -0
  266. package/.next/static/chunks/394.91597771688df6d0.js +1 -0
  267. package/.next/static/chunks/3997.1009c06025691712.js +1 -0
  268. package/.next/static/chunks/4453.91a357dc43c21745.js +1 -0
  269. package/.next/static/chunks/4491.44fdf20580ac72bd.js +24 -0
  270. package/.next/static/chunks/4829.cf1d50e43e6d9db5.js +1 -0
  271. package/.next/static/chunks/498.fe1d9da9ecad6c36.js +1 -0
  272. package/.next/static/chunks/4bd1b696-e356ca5ba0218e27.js +1 -0
  273. package/.next/static/chunks/5019.b5a1a2b8daf17525.js +1 -0
  274. package/.next/static/chunks/5034.8f16c3fa3ce75411.js +1 -0
  275. package/.next/static/chunks/5074.d16651da01ec4e02.js +1 -0
  276. package/.next/static/chunks/51fb665c.0950e1b79671348d.js +45 -0
  277. package/.next/static/chunks/532.5956ed631aff722b.js +9 -0
  278. package/.next/static/chunks/5326.69460442bdcd6cd3.js +1 -0
  279. package/.next/static/chunks/5403.ff110bf5bf600758.js +64 -0
  280. package/.next/static/chunks/547.902a733488cfe3f7.js +77 -0
  281. package/.next/static/chunks/5567.540d7fc108ad6ee5.js +215 -0
  282. package/.next/static/chunks/5590.ef62922166d308b4.js +1 -0
  283. package/.next/static/chunks/5690.9d6eb1edb1399995.js +1 -0
  284. package/.next/static/chunks/5749.25faee4a1e55b854.js +226 -0
  285. package/.next/static/chunks/58bb9007.1ccb6bba34b4c635.js +80 -0
  286. package/.next/static/chunks/6121.f3f43f1896ea0cd9.js +1 -0
  287. package/.next/static/chunks/6600.583c88eef37aa524.js +1 -0
  288. package/.next/static/chunks/6696.a41aec266e657d54.js +141 -0
  289. package/.next/static/chunks/6922.42148793782d2fe7.js +1 -0
  290. package/.next/static/chunks/7006.e191611ffc2b9528.js +43 -0
  291. package/.next/static/chunks/7343.9fbb58204d8ac681.js +1 -0
  292. package/.next/static/chunks/73972abe.25a4cffa03b2bcef.js +119 -0
  293. package/.next/static/chunks/7547.58bda8a2aabba0d4.js +93 -0
  294. package/.next/static/chunks/7648.4ae2f183b4db0353.js +1 -0
  295. package/.next/static/chunks/7874.8db6929b94cdf697.js +1 -0
  296. package/.next/static/chunks/7959.1f20a35df316216a.js +104 -0
  297. package/.next/static/chunks/83.85d62d7fc9850b75.js +29 -0
  298. package/.next/static/chunks/8436.cab94b59cca0a8ff.js +1 -0
  299. package/.next/static/chunks/8451.ff6ff72b57dc52e1.js +1 -0
  300. package/.next/static/chunks/8489.45f22859734f514f.js +36 -0
  301. package/.next/static/chunks/8568.f85d8b36fc9a9037.js +1 -0
  302. package/.next/static/chunks/8771-3e14b6810486df1f.js +1 -0
  303. package/.next/static/chunks/8863.be51033a67436277.js +1 -0
  304. package/.next/static/chunks/90542734.dc1a2723e4f6affb.js +1 -0
  305. package/.next/static/chunks/9500.1488aec06ee78127.js +1 -0
  306. package/.next/static/chunks/9633.155548b5fca6e580.js +1 -0
  307. package/.next/static/chunks/9779.673004a62d70e36a.js +1 -0
  308. package/.next/static/chunks/app/_global-error/page-cc518af6b1ffb191.js +1 -0
  309. package/.next/static/chunks/app/_not-found/page-c72daab99269beff.js +1 -0
  310. package/.next/static/chunks/app/api/agent/[id]/events/route-cc518af6b1ffb191.js +1 -0
  311. package/.next/static/chunks/app/api/agent/[id]/route-cc518af6b1ffb191.js +1 -0
  312. package/.next/static/chunks/app/api/agent/new/route-cc518af6b1ffb191.js +1 -0
  313. package/.next/static/chunks/app/api/auth/all-providers/route-cc518af6b1ffb191.js +1 -0
  314. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-cc518af6b1ffb191.js +1 -0
  315. package/.next/static/chunks/app/api/auth/login/[provider]/route-cc518af6b1ffb191.js +1 -0
  316. package/.next/static/chunks/app/api/auth/login/route-cc518af6b1ffb191.js +1 -0
  317. package/.next/static/chunks/app/api/auth/logout/[provider]/route-cc518af6b1ffb191.js +1 -0
  318. package/.next/static/chunks/app/api/auth/providers/route-cc518af6b1ffb191.js +1 -0
  319. package/.next/static/chunks/app/api/auth/status/route-cc518af6b1ffb191.js +1 -0
  320. package/.next/static/chunks/app/api/default-cwd/route-cc518af6b1ffb191.js +1 -0
  321. package/.next/static/chunks/app/api/files/[...path]/route-cc518af6b1ffb191.js +1 -0
  322. package/.next/static/chunks/app/api/harness/route-cc518af6b1ffb191.js +1 -0
  323. package/.next/static/chunks/app/api/home/route-cc518af6b1ffb191.js +1 -0
  324. package/.next/static/chunks/app/api/internal/runtime/route-cc518af6b1ffb191.js +1 -0
  325. package/.next/static/chunks/app/api/models/route-cc518af6b1ffb191.js +1 -0
  326. package/.next/static/chunks/app/api/models-config/discover/route-cc518af6b1ffb191.js +1 -0
  327. package/.next/static/chunks/app/api/models-config/route-cc518af6b1ffb191.js +1 -0
  328. package/.next/static/chunks/app/api/models-config/test/route-cc518af6b1ffb191.js +1 -0
  329. package/.next/static/chunks/app/api/projects/browse/route-cc518af6b1ffb191.js +1 -0
  330. package/.next/static/chunks/app/api/projects/route-cc518af6b1ffb191.js +1 -0
  331. package/.next/static/chunks/app/api/reports/[id]/route-cc518af6b1ffb191.js +1 -0
  332. package/.next/static/chunks/app/api/search/route-cc518af6b1ffb191.js +1 -0
  333. package/.next/static/chunks/app/api/sessions/[id]/context/route-cc518af6b1ffb191.js +1 -0
  334. package/.next/static/chunks/app/api/sessions/[id]/route-cc518af6b1ffb191.js +1 -0
  335. package/.next/static/chunks/app/api/sessions/new/route-cc518af6b1ffb191.js +1 -0
  336. package/.next/static/chunks/app/api/sessions/route-cc518af6b1ffb191.js +1 -0
  337. package/.next/static/chunks/app/api/settings/route-cc518af6b1ffb191.js +1 -0
  338. package/.next/static/chunks/app/api/skills/install/route-cc518af6b1ffb191.js +1 -0
  339. package/.next/static/chunks/app/api/skills/route-cc518af6b1ffb191.js +1 -0
  340. package/.next/static/chunks/app/api/skills/search/route-cc518af6b1ffb191.js +1 -0
  341. package/.next/static/chunks/app/api/soul/route-cc518af6b1ffb191.js +1 -0
  342. package/.next/static/chunks/app/api/version/route-cc518af6b1ffb191.js +1 -0
  343. package/.next/static/chunks/app/layout-be148b7ae915b22a.js +1 -0
  344. package/.next/static/chunks/app/login/page-ebf0e6de99062783.js +1 -0
  345. package/.next/static/chunks/app/page-0594cb7a3cbb0211.js +260 -0
  346. package/.next/static/chunks/d3ac728e.7964f816a1ca64e5.js +1 -0
  347. package/.next/static/chunks/framework-711ef29bc66f648c.js +1 -0
  348. package/.next/static/chunks/main-app-45a0f19af99d61b6.js +1 -0
  349. package/.next/static/chunks/main-f74964b7ae52493e.js +5 -0
  350. package/.next/static/chunks/next/dist/client/components/builtin/app-error-cc518af6b1ffb191.js +1 -0
  351. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-cc518af6b1ffb191.js +1 -0
  352. package/.next/static/chunks/next/dist/client/components/builtin/global-error-9bfa08b9491621f2.js +1 -0
  353. package/.next/static/chunks/next/dist/client/components/builtin/not-found-cc518af6b1ffb191.js +1 -0
  354. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-cc518af6b1ffb191.js +1 -0
  355. package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  356. package/.next/static/chunks/webpack-fcf4a889ecbd753c.js +1 -0
  357. package/.next/static/css/45029451a1d7255d.css +3 -0
  358. package/.next/static/media/15605e25b523335c-s.woff2 +0 -0
  359. package/.next/static/media/1a3dce5cfb5f7760-s.woff2 +0 -0
  360. package/.next/static/media/1cdd02902f937a18-s.woff2 +0 -0
  361. package/.next/static/media/4c4b3b30b6bcb2be-s.woff2 +0 -0
  362. package/.next/static/media/641a7b8a5800ee0e-s.woff2 +0 -0
  363. package/.next/static/media/7deddc85b7ffd1dc-s.p.woff2 +0 -0
  364. package/.next/static/media/ec14413c594b3356-s.p.woff2 +0 -0
  365. package/.next/static/media/pdf.worker.min.29aaf158.mjs +6 -0
  366. package/.next/static/nmfQlwnkhzbPmuiCmhW-_/_buildManifest.js +1 -0
  367. package/.next/static/nmfQlwnkhzbPmuiCmhW-_/_ssgManifest.js +1 -0
  368. package/package.json +21 -21
  369. package/app/api/agent/[id]/events/route.ts +0 -94
  370. package/app/api/agent/[id]/route.ts +0 -83
  371. package/app/api/agent/new/route.ts +0 -53
  372. package/app/api/auth/all-providers/route.ts +0 -21
  373. package/app/api/auth/api-key/[provider]/route.ts +0 -7
  374. package/app/api/auth/login/[provider]/route.ts +0 -7
  375. package/app/api/auth/login/route.ts +0 -22
  376. package/app/api/auth/logout/[provider]/route.ts +0 -7
  377. package/app/api/auth/providers/route.ts +0 -15
  378. package/app/api/auth/status/route.ts +0 -6
  379. package/app/api/default-cwd/route.ts +0 -22
  380. package/app/api/files/[...path]/route.ts +0 -621
  381. package/app/api/harness/route.ts +0 -47
  382. package/app/api/home/route.ts +0 -6
  383. package/app/api/internal/runtime/route.ts +0 -26
  384. package/app/api/models/route.ts +0 -67
  385. package/app/api/models-config/discover/route.ts +0 -42
  386. package/app/api/models-config/route.ts +0 -152
  387. package/app/api/models-config/test/route.ts +0 -154
  388. package/app/api/projects/browse/route.ts +0 -51
  389. package/app/api/projects/route.ts +0 -83
  390. package/app/api/reports/[id]/route.ts +0 -108
  391. package/app/api/search/route.ts +0 -122
  392. package/app/api/sessions/[id]/context/route.ts +0 -23
  393. package/app/api/sessions/[id]/route.ts +0 -124
  394. package/app/api/sessions/new/route.ts +0 -5
  395. package/app/api/sessions/route.ts +0 -16
  396. package/app/api/settings/route.ts +0 -51
  397. package/app/api/skills/install/route.ts +0 -249
  398. package/app/api/skills/route.ts +0 -161
  399. package/app/api/skills/search/route.ts +0 -121
  400. package/app/api/soul/route.ts +0 -47
  401. package/app/api/version/route.ts +0 -55
  402. package/app/globals.css +0 -736
  403. package/app/layout.tsx +0 -40
  404. package/app/login/page.tsx +0 -133
  405. package/app/page.tsx +0 -10
  406. package/components/AppShell.tsx +0 -1058
  407. package/components/ChatInput.tsx +0 -1103
  408. package/components/ChatMinimap.tsx +0 -381
  409. package/components/ChatWindow.tsx +0 -576
  410. package/components/CodeMirrorEditor.tsx +0 -137
  411. package/components/ConversationSearch.tsx +0 -369
  412. package/components/DataTableViewer.tsx +0 -248
  413. package/components/FileExplorer.tsx +0 -758
  414. package/components/FileIcons.tsx +0 -241
  415. package/components/FileViewer.tsx +0 -1273
  416. package/components/GlobalFileEditor.tsx +0 -98
  417. package/components/MarkdownRenderer.tsx +0 -331
  418. package/components/MermaidDiagram.tsx +0 -80
  419. package/components/MessageView.tsx +0 -1141
  420. package/components/ModelsConfig.tsx +0 -1991
  421. package/components/ProjectContext.tsx +0 -252
  422. package/components/ProjectFolderPicker.tsx +0 -202
  423. package/components/ProjectsConfig.tsx +0 -288
  424. package/components/ProviderIcons.tsx +0 -91
  425. package/components/ReportPanel.tsx +0 -237
  426. package/components/ResizeHandle.tsx +0 -105
  427. package/components/SessionSidebar.tsx +0 -1464
  428. package/components/SettingsDialog.tsx +0 -287
  429. package/components/SkillsConfig.tsx +0 -1093
  430. package/components/SubagentPanel.tsx +0 -191
  431. package/components/TabBar.tsx +0 -115
  432. package/components/ToolPanel.tsx +0 -131
  433. package/components/WidgetRenderer.tsx +0 -505
  434. package/components/viewers/DocumentToolbar.tsx +0 -78
  435. package/components/viewers/DocxViewer.tsx +0 -97
  436. package/components/viewers/PdfViewer.tsx +0 -206
  437. package/components/viewers/PptxViewer.tsx +0 -240
  438. package/components/viewers/XlsxViewer.tsx +0 -143
  439. package/hooks/useAgentSession.ts +0 -710
  440. package/hooks/useAudio.ts +0 -50
  441. package/hooks/useDragDrop.ts +0 -52
  442. package/hooks/useResizable.ts +0 -60
  443. package/hooks/useTheme.ts +0 -85
  444. package/lib/agent-client.ts +0 -39
  445. package/lib/annodex-config.ts +0 -556
  446. package/lib/auth-token.ts +0 -74
  447. package/lib/auth.ts +0 -90
  448. package/lib/brand.ts +0 -5
  449. package/lib/code-theme.ts +0 -32
  450. package/lib/codex-compat-proxy.ts +0 -1603
  451. package/lib/codex-home.ts +0 -6
  452. package/lib/codex-server.ts +0 -796
  453. package/lib/codex-session.ts +0 -590
  454. package/lib/codex-usage.ts +0 -213
  455. package/lib/file-paths.ts +0 -34
  456. package/lib/model-discovery.ts +0 -379
  457. package/lib/normalize.ts +0 -30
  458. package/lib/npx.ts +0 -87
  459. package/lib/pi-types.ts +0 -49
  460. package/lib/projects.ts +0 -269
  461. package/lib/provider-api.ts +0 -88
  462. package/lib/report-prompt.ts +0 -61
  463. package/lib/report-store.ts +0 -597
  464. package/lib/report-update-parser.ts +0 -66
  465. package/lib/rpc-manager.ts +0 -668
  466. package/lib/runtime-state.ts +0 -117
  467. package/lib/session-reader.ts +0 -903
  468. package/lib/session-runtime.ts +0 -105
  469. package/lib/subagent-progress.ts +0 -279
  470. package/lib/types.ts +0 -241
  471. package/lib/widget-export.ts +0 -318
  472. package/lib/widget-guidelines.ts +0 -288
  473. package/lib/widget-prompt.ts +0 -76
  474. package/lib/widget-utils.ts +0 -523
  475. package/postcss.config.mjs +0 -8
  476. package/proxy.ts +0 -64
  477. package/scripts/postinstall.cjs +0 -25
  478. package/tsconfig.json +0 -41
@@ -1,1103 +0,0 @@
1
- "use client";
2
-
3
- import React, { useRef, useState, useCallback, useEffect, useImperativeHandle, forwardRef, KeyboardEvent } from "react";
4
-
5
- export interface AttachedImage {
6
- data: string; // base64, no prefix
7
- mimeType: string;
8
- previewUrl: string; // object URL for display
9
- }
10
-
11
- export interface AttachedDocument {
12
- data: ArrayBuffer;
13
- fileName: string;
14
- mimeType: string;
15
- size: number;
16
- extractedText?: string;
17
- extractionError?: string;
18
- truncated?: boolean;
19
- }
20
-
21
- interface ModelOption {
22
- provider: string;
23
- modelId: string;
24
- name: string;
25
- }
26
-
27
- interface Props {
28
- onSend: (message: string, images?: AttachedImage[], documents?: AttachedDocument[]) => void;
29
- onAbort: () => void;
30
- isStreaming: boolean;
31
- model?: { provider: string; modelId: string } | null;
32
- modelNames?: Record<string, string>;
33
- modelList?: { id: string; name: string; provider: string }[];
34
- onModelChange?: (provider: string, modelId: string) => void;
35
- onCompact?: () => void;
36
- onAbortCompaction?: () => void;
37
- isCompacting?: boolean;
38
- compactError?: string | null;
39
- toolPreset?: "none" | "default" | "full";
40
- onToolPresetChange?: (preset: "none" | "default" | "full") => void;
41
- thinkingLevel?: "auto" | "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
42
- onThinkingLevelChange?: (level: "auto" | "off" | "minimal" | "low" | "medium" | "high" | "xhigh") => void;
43
- availableThinkingLevels?: string[] | null;
44
- thinkingLevelMap?: Record<string, string | null> | null;
45
- retryInfo?: { attempt: number; maxAttempts: number; errorMessage?: string } | null;
46
- soundEnabled?: boolean;
47
- onSoundToggle?: () => void;
48
- }
49
-
50
- export interface ChatInputHandle {
51
- insertText: (text: string) => void;
52
- insertIfEmpty: (text: string) => void;
53
- addImages: (files: File[]) => void;
54
- addFiles: (files: File[]) => void;
55
- }
56
-
57
- const TOOL_PRESETS = ["off", "default", "full"] as const;
58
- const TOOL_PRESET_MAP: Record<typeof TOOL_PRESETS[number], "none" | "default" | "full"> = { off: "none", default: "default", full: "full" };
59
-
60
- const THINKING_LEVELS = ["auto", "off", "minimal", "low", "medium", "high", "xhigh"] as const;
61
- const THINKING_LEVEL_DESC: Record<typeof THINKING_LEVELS[number], string> = {
62
- auto: "沿用默认设置",
63
- off: "关闭推理",
64
- minimal: "最少推理",
65
- low: "低强度推理",
66
- medium: "中等推理",
67
- high: "高强度推理",
68
- xhigh: "最高强度推理",
69
- };
70
-
71
- function DocAttachmentPreview({ doc, onRemove }: { doc: AttachedDocument; onRemove: () => void }) {
72
- const ext = doc.fileName.split(".").pop()?.toLowerCase() ?? "";
73
- const icon = getDocIcon(ext);
74
- const sizeStr = formatDocSize(doc.size);
75
-
76
- return (
77
- <div
78
- style={{
79
- position: "relative",
80
- display: "flex",
81
- alignItems: "center",
82
- gap: 6,
83
- padding: "5px 10px 5px 7px",
84
- background: "var(--bg-panel)",
85
- border: "1px solid var(--border)",
86
- borderRadius: 6,
87
- maxWidth: 200,
88
- }}
89
- title={doc.fileName}
90
- >
91
- <span style={{ color: icon.color, fontSize: 14, flexShrink: 0 }}>{icon.emoji}</span>
92
- <div style={{ minWidth: 0, flex: 1 }}>
93
- <div
94
- style={{
95
- fontSize: 11,
96
- color: "var(--text)",
97
- overflow: "hidden",
98
- textOverflow: "ellipsis",
99
- whiteSpace: "nowrap",
100
- lineHeight: 1.3,
101
- }}
102
- >
103
- {doc.fileName}
104
- </div>
105
- <div style={{ fontSize: 10, color: "var(--text-dim)", lineHeight: 1.3 }}>
106
- {ext.toUpperCase()} · {sizeStr}{doc.extractionError ? " · no text" : doc.truncated ? " · truncated" : doc.extractedText ? " · text" : ""}
107
- </div>
108
- </div>
109
- <button
110
- onClick={onRemove}
111
- style={{
112
- flexShrink: 0,
113
- width: 14,
114
- height: 14,
115
- borderRadius: "50%",
116
- background: "var(--bg-hover)",
117
- border: "none",
118
- display: "flex",
119
- alignItems: "center",
120
- justifyContent: "center",
121
- cursor: "pointer",
122
- padding: 0,
123
- color: "var(--text-dim)",
124
- }}
125
- onMouseEnter={(e) => { e.currentTarget.style.color = "var(--text)"; }}
126
- onMouseLeave={(e) => { e.currentTarget.style.color = "var(--text-dim)"; }}
127
- >
128
- <svg width="7" height="7" viewBox="0 0 7 7" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
129
- <line x1="1" y1="1" x2="6" y2="6" /><line x1="6" y1="1" x2="1" y2="6" />
130
- </svg>
131
- </button>
132
- </div>
133
- );
134
- }
135
-
136
- function getDocIcon(ext: string): { emoji: string; color: string } {
137
- switch (ext) {
138
- case "pdf": return { emoji: "📄", color: "#ef4444" };
139
- case "docx":
140
- case "doc": return { emoji: "📝", color: "#3b82f6" };
141
- case "xlsx":
142
- case "xls": return { emoji: "📊", color: "#22c55e" };
143
- case "pptx":
144
- case "ppt": return { emoji: "📽", color: "#f97316" };
145
- default: return { emoji: "📎", color: "var(--text-muted)" };
146
- }
147
- }
148
-
149
- function formatDocSize(bytes: number): string {
150
- if (bytes < 1024) return `${bytes} B`;
151
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
152
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
153
- }
154
-
155
- const DOCUMENT_TEXT_MAX_CHARS = 60_000;
156
-
157
- function truncateDocumentText(text: string): { text: string; truncated: boolean } {
158
- const clean = text.replace(/\r\n/g, "\n").replace(/\n{4,}/g, "\n\n\n").trim();
159
- if (clean.length <= DOCUMENT_TEXT_MAX_CHARS) return { text: clean, truncated: false };
160
- return {
161
- text: `${clean.slice(0, DOCUMENT_TEXT_MAX_CHARS)}\n\n[truncated after ${DOCUMENT_TEXT_MAX_CHARS} characters]`,
162
- truncated: true,
163
- };
164
- }
165
-
166
- function decodeXmlText(value: string): string {
167
- return value
168
- .replace(/&lt;/g, "<")
169
- .replace(/&gt;/g, ">")
170
- .replace(/&amp;/g, "&")
171
- .replace(/&quot;/g, "\"")
172
- .replace(/&apos;/g, "'");
173
- }
174
-
175
- async function extractPdfText(arrayBuffer: ArrayBuffer): Promise<string> {
176
- const pdfjsLib = await import("pdfjs-dist/legacy/build/pdf.mjs") as typeof import("pdfjs-dist");
177
- pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
178
- "pdfjs-dist/legacy/build/pdf.worker.min.mjs",
179
- import.meta.url
180
- ).toString();
181
- const doc = await pdfjsLib.getDocument({ data: arrayBuffer.slice(0) }).promise;
182
- const pages: string[] = [];
183
- for (let pageNum = 1; pageNum <= doc.numPages; pageNum += 1) {
184
- const page = await doc.getPage(pageNum);
185
- const textContent = await page.getTextContent();
186
- const text = textContent.items
187
- .map((item) => "str" in item ? item.str : "")
188
- .filter(Boolean)
189
- .join(" ");
190
- if (text.trim()) pages.push(`Page ${pageNum}\n${text}`);
191
- }
192
- return pages.join("\n\n");
193
- }
194
-
195
- async function extractDocxText(arrayBuffer: ArrayBuffer): Promise<string> {
196
- const JSZip = (await import("jszip")).default;
197
- const zip = await JSZip.loadAsync(arrayBuffer);
198
- const parts = [
199
- "word/document.xml",
200
- ...Object.keys(zip.files)
201
- .filter((name) => /^word\/(footnotes|endnotes|comments)\.xml$/i.test(name))
202
- .sort(),
203
- ];
204
- const chunks: string[] = [];
205
- for (const part of parts) {
206
- const file = zip.file(part);
207
- if (!file) continue;
208
- const xml = await file.async("string");
209
- const withBreaks = xml
210
- .replace(/<w:(br|cr)[^>]*\/>/g, "\n")
211
- .replace(/<\/w:p>/g, "\n");
212
- const matches = [...withBreaks.matchAll(/<w:t[^>]*>([\s\S]*?)<\/w:t>/g)];
213
- chunks.push(...matches.map((match) => decodeXmlText(match[1])));
214
- }
215
- return chunks.join("").replace(/[ \t]+\n/g, "\n");
216
- }
217
-
218
- async function extractXlsxText(arrayBuffer: ArrayBuffer): Promise<string> {
219
- const XLSX = await import("xlsx");
220
- const workbook = XLSX.read(arrayBuffer, { type: "array" });
221
- return workbook.SheetNames.map((name) => {
222
- const sheet = workbook.Sheets[name];
223
- const csv = XLSX.utils.sheet_to_csv(sheet);
224
- return `Sheet: ${name}\n${csv}`;
225
- }).join("\n\n");
226
- }
227
-
228
- async function extractPptxText(arrayBuffer: ArrayBuffer): Promise<string> {
229
- const JSZip = (await import("jszip")).default;
230
- const zip = await JSZip.loadAsync(arrayBuffer);
231
- const slideFiles = Object.keys(zip.files)
232
- .map((name) => ({ name, match: /^ppt\/slides\/slide(\d+)\.xml$/i.exec(name) }))
233
- .filter((item): item is { name: string; match: RegExpExecArray } => item.match !== null)
234
- .sort((a, b) => Number(a.match[1]) - Number(b.match[1]));
235
- const slides: string[] = [];
236
- for (const { name, match } of slideFiles) {
237
- const xml = await zip.file(name)!.async("string");
238
- const texts = [...xml.matchAll(/<a:t[^>]*>([\s\S]*?)<\/a:t>/g)]
239
- .map((m) => decodeXmlText(m[1]).trim())
240
- .filter(Boolean);
241
- if (texts.length) slides.push(`Slide ${match[1]}\n${texts.join("\n")}`);
242
- }
243
- return slides.join("\n\n");
244
- }
245
-
246
- async function extractDocumentText(file: File, arrayBuffer: ArrayBuffer): Promise<Pick<AttachedDocument, "extractedText" | "extractionError" | "truncated">> {
247
- const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
248
- try {
249
- let raw = "";
250
- if (file.type.startsWith("text/") || ["csv", "tsv", "md", "txt", "json", "xml"].includes(ext)) {
251
- raw = new TextDecoder("utf-8").decode(arrayBuffer);
252
- } else if (ext === "pdf" || file.type === "application/pdf") {
253
- raw = await extractPdfText(arrayBuffer);
254
- } else if (ext === "docx") {
255
- raw = await extractDocxText(arrayBuffer);
256
- } else if (ext === "xlsx") {
257
- raw = await extractXlsxText(arrayBuffer);
258
- } else if (ext === "pptx") {
259
- raw = await extractPptxText(arrayBuffer);
260
- } else {
261
- return { extractionError: "Text extraction is not supported for this file type" };
262
- }
263
- const { text, truncated } = truncateDocumentText(raw);
264
- if (!text) return { extractionError: "No extractable text found" };
265
- return { extractedText: text, truncated };
266
- } catch (error) {
267
- return { extractionError: error instanceof Error ? error.message : String(error) };
268
- }
269
- }
270
-
271
- export const ChatInput = forwardRef<ChatInputHandle, Props>(function ChatInput({
272
- onSend, onAbort, isStreaming, model, modelNames, modelList, onModelChange,
273
- onCompact, onAbortCompaction, isCompacting, compactError, toolPreset, onToolPresetChange,
274
- thinkingLevel, onThinkingLevelChange, availableThinkingLevels, thinkingLevelMap,
275
- retryInfo,
276
- soundEnabled, onSoundToggle,
277
- }: Props, ref) {
278
- const [value, setValue] = useState("");
279
- const [modelDropdownOpen, setModelDropdownOpen] = useState(false);
280
- const [modelDropdownRect, setModelDropdownRect] = useState<{ top: number; left: number; width: number } | null>(null);
281
- const [toolDropdownOpen, setToolDropdownOpen] = useState(false);
282
- const [thinkingDropdownOpen, setThinkingDropdownOpen] = useState(false);
283
- const [attachedImages, setAttachedImages] = useState<AttachedImage[]>([]);
284
- const [attachedDocs, setAttachedDocs] = useState<AttachedDocument[]>([]);
285
-
286
- const textareaRef = useRef<HTMLTextAreaElement>(null);
287
- const dropdownRef = useRef<HTMLDivElement>(null);
288
- const modelDropdownPanelRef = useRef<HTMLDivElement>(null);
289
- const toolDropdownRef = useRef<HTMLDivElement>(null);
290
- const thinkingDropdownRef = useRef<HTMLDivElement>(null);
291
- const fileInputRef = useRef<HTMLInputElement>(null);
292
- const docInputRef = useRef<HTMLInputElement>(null);
293
-
294
- useImperativeHandle(ref, () => ({
295
- insertIfEmpty(text: string) {
296
- const ta = textareaRef.current;
297
- const current = ta ? ta.value : value;
298
- if (current.trim()) return;
299
- setValue(text);
300
- requestAnimationFrame(() => {
301
- if (!ta) return;
302
- ta.focus();
303
- ta.style.height = "auto";
304
- ta.style.height = `${Math.min(ta.scrollHeight, 200)}px`;
305
- });
306
- },
307
- insertText(text: string) {
308
- const ta = textareaRef.current;
309
- if (!ta) {
310
- setValue((v) => v + (v ? " " : "") + text);
311
- return;
312
- }
313
- const start = ta.selectionStart ?? ta.value.length;
314
- const end = ta.selectionEnd ?? ta.value.length;
315
- const before = ta.value.slice(0, start);
316
- const after = ta.value.slice(end);
317
- const sep = before.length > 0 && !before.endsWith(" ") ? " " : "";
318
- const newVal = before + sep + text + after;
319
- setValue(newVal);
320
- requestAnimationFrame(() => {
321
- if (!ta) return;
322
- const pos = start + sep.length + text.length;
323
- ta.setSelectionRange(pos, pos);
324
- ta.focus();
325
- ta.style.height = "auto";
326
- ta.style.height = `${Math.min(ta.scrollHeight, 200)}px`;
327
- });
328
- },
329
- addImages(files: File[]) {
330
- processImageFiles(files);
331
- },
332
- addFiles(files: File[]) {
333
- processFiles(files);
334
- },
335
- }));
336
-
337
- const processImageFiles = useCallback(async (files: File[]) => {
338
- const imageFiles = files.filter((f) => f.type.startsWith("image/"));
339
- if (!imageFiles.length) return;
340
- const newImages = await Promise.all(
341
- imageFiles.map(
342
- (file) =>
343
- new Promise<AttachedImage>((resolve, reject) => {
344
- const reader = new FileReader();
345
- reader.onload = () => {
346
- const result = reader.result as string;
347
- const base64 = result.split(",")[1];
348
- resolve({ data: base64, mimeType: file.type, previewUrl: URL.createObjectURL(file) });
349
- };
350
- reader.onerror = reject;
351
- reader.readAsDataURL(file);
352
- })
353
- )
354
- );
355
- setAttachedImages((prev) => [...prev, ...newImages]);
356
- }, []);
357
-
358
- const processFiles = useCallback(async (files: File[]) => {
359
- const imageFiles = files.filter((f) => f.type.startsWith("image/"));
360
- const docFiles = files.filter((f) => !f.type.startsWith("image/"));
361
-
362
- // Process images
363
- if (imageFiles.length) {
364
- processImageFiles(imageFiles);
365
- }
366
-
367
- // Process documents
368
- if (docFiles.length) {
369
- const newDocs = await Promise.all(
370
- docFiles.map(
371
- (file) =>
372
- new Promise<AttachedDocument>((resolve, reject) => {
373
- const reader = new FileReader();
374
- reader.onload = async () => {
375
- const data = reader.result as ArrayBuffer;
376
- const extraction = await extractDocumentText(file, data);
377
- resolve({
378
- data,
379
- fileName: file.name,
380
- mimeType: file.type || "application/octet-stream",
381
- size: file.size,
382
- ...extraction,
383
- });
384
- };
385
- reader.onerror = reject;
386
- reader.readAsArrayBuffer(file);
387
- })
388
- )
389
- );
390
- setAttachedDocs((prev) => [...prev, ...newDocs]);
391
- }
392
- }, [processImageFiles]);
393
-
394
- const removeImage = useCallback((index: number) => {
395
- setAttachedImages((prev) => {
396
- const next = [...prev];
397
- URL.revokeObjectURL(next[index].previewUrl);
398
- next.splice(index, 1);
399
- return next;
400
- });
401
- }, []);
402
-
403
- const removeDoc = useCallback((index: number) => {
404
- setAttachedDocs((prev) => {
405
- const next = [...prev];
406
- next.splice(index, 1);
407
- return next;
408
- });
409
- }, []);
410
-
411
- const clearAttachments = useCallback(() => {
412
- setAttachedImages((prev) => {
413
- prev.forEach((img) => URL.revokeObjectURL(img.previewUrl));
414
- return [];
415
- });
416
- setAttachedDocs([]);
417
- }, []);
418
-
419
- const handleSend = useCallback(() => {
420
- const msg = value.trim();
421
- if (!msg && !attachedImages.length && !attachedDocs.length) return;
422
- if (isStreaming) return;
423
- onSend(
424
- msg,
425
- attachedImages.length ? attachedImages : undefined,
426
- attachedDocs.length ? attachedDocs : undefined
427
- );
428
- setValue("");
429
- clearAttachments();
430
- if (textareaRef.current) {
431
- textareaRef.current.style.height = "auto";
432
- }
433
- }, [value, attachedImages, attachedDocs, isStreaming, onSend, clearAttachments]);
434
-
435
- const handleKeyDown = useCallback(
436
- (e: KeyboardEvent<HTMLTextAreaElement>) => {
437
- if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
438
- e.preventDefault();
439
- handleSend();
440
- }
441
- },
442
- [handleSend]
443
- );
444
-
445
- const handleInput = useCallback(() => {
446
- const ta = textareaRef.current;
447
- if (!ta) return;
448
- ta.style.height = "auto";
449
- ta.style.height = `${Math.min(ta.scrollHeight, 200)}px`;
450
- }, []);
451
-
452
- const handlePaste = useCallback((e: React.ClipboardEvent) => {
453
- const items = Array.from(e.clipboardData?.items ?? []);
454
- const fileItems = items.filter((item) => item.kind === "file" && (item.type.startsWith("image/") || item.type.includes("pdf") || item.type.includes("officedocument") || item.type.includes("msword") || item.type.includes("ms-")));
455
- if (!fileItems.length) return;
456
- e.preventDefault();
457
- const files = fileItems.map((item) => item.getAsFile()).filter((f): f is File => f !== null);
458
- processFiles(files);
459
- }, [processFiles]);
460
-
461
-
462
-
463
- // Build model options: prefer modelList (has provider info), fallback to modelNames
464
- const modelOptions: ModelOption[] = (() => {
465
- if (modelList && modelList.length > 0) {
466
- return modelList.map((m) => ({ provider: m.provider, modelId: m.id, name: m.name }));
467
- }
468
- return Object.entries(modelNames ?? {}).map(([modelId, name]) => ({
469
- provider: model?.provider ?? "unknown",
470
- modelId,
471
- name,
472
- }));
473
- })();
474
-
475
- // Group options by provider, preserving insertion order
476
- const modelsByProvider: { provider: string; options: ModelOption[] }[] = [];
477
- for (const opt of modelOptions) {
478
- const group = modelsByProvider.find((g) => g.provider === opt.provider);
479
- if (group) group.options.push(opt);
480
- else modelsByProvider.push({ provider: opt.provider, options: [opt] });
481
- }
482
-
483
- const currentName = model
484
- ? (modelOptions.find((o) => o.modelId === model.modelId && o.provider === model.provider)?.name ?? model.modelId)
485
- : "Select model";
486
-
487
- // Close dropdowns on outside click
488
- useEffect(() => {
489
- const handler = (e: MouseEvent) => {
490
- if (
491
- dropdownRef.current && !dropdownRef.current.contains(e.target as Node) &&
492
- modelDropdownPanelRef.current && !modelDropdownPanelRef.current.contains(e.target as Node)
493
- ) {
494
- setModelDropdownOpen(false);
495
- }
496
- if (toolDropdownRef.current && !toolDropdownRef.current.contains(e.target as Node)) {
497
- setToolDropdownOpen(false);
498
- }
499
- if (thinkingDropdownRef.current && !thinkingDropdownRef.current.contains(e.target as Node)) {
500
- setThinkingDropdownOpen(false);
501
- }
502
- };
503
- document.addEventListener("mousedown", handler);
504
- return () => document.removeEventListener("mousedown", handler);
505
- }, []);
506
-
507
-
508
-
509
- return (
510
- <div
511
- style={{
512
- flexShrink: 0,
513
- background: "transparent",
514
- padding: "0 16px 8px",
515
- paddingRight: 52, // 16px base + 36px for ChatMinimap alignment
516
- }}
517
- >
518
- {/* Hidden file inputs */}
519
- <input
520
- ref={fileInputRef}
521
- type="file"
522
- accept="image/*"
523
- multiple
524
- style={{ display: "none" }}
525
- onChange={(e) => {
526
- const files = Array.from(e.target.files ?? []);
527
- processImageFiles(files);
528
- e.target.value = "";
529
- }}
530
- />
531
- <input
532
- ref={docInputRef}
533
- type="file"
534
- accept=".pdf,.docx,.xlsx,.pptx,.doc,.xls,.ppt,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.openxmlformats-officedocument.presentationml.presentation"
535
- multiple
536
- style={{ display: "none" }}
537
- onChange={(e) => {
538
- const files = Array.from(e.target.files ?? []);
539
- processFiles(files);
540
- e.target.value = "";
541
- }}
542
- />
543
- <div style={{ maxWidth: 820, margin: "0 auto" }}>
544
- {/* Retry banner */}
545
- {retryInfo && (
546
- <div style={{
547
- marginBottom: 8, padding: "5px 10px",
548
- background: "rgba(234,179,8,0.08)", border: "1px solid rgba(234,179,8,0.25)",
549
- borderRadius: 6, fontSize: 12, color: "rgba(180,130,0,0.9)",
550
- display: "flex", alignItems: "center", gap: 6,
551
- }}>
552
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
553
- <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
554
- <path d="M3 3v5h5" />
555
- </svg>
556
- Retrying ({retryInfo.attempt}/{retryInfo.maxAttempts})…{retryInfo.errorMessage && <span style={{ opacity: 0.7, marginLeft: 4 }}>— {retryInfo.errorMessage}</span>}
557
- </div>
558
- )}
559
- {/* Attachments preview */}
560
- {(attachedImages.length > 0 || attachedDocs.length > 0) && (
561
- <div style={{ display: "flex", gap: 6, marginBottom: 6, flexWrap: "wrap", alignItems: "flex-end" }}>
562
- {attachedImages.map((img, i) => (
563
- <div key={`img-${i}`} style={{ position: "relative", flexShrink: 0 }}>
564
- {/* eslint-disable-next-line @next/next/no-img-element */}
565
- <img
566
- src={img.previewUrl}
567
- alt=""
568
- style={{ width: 56, height: 56, objectFit: "cover", borderRadius: 6, border: "1px solid var(--border)", display: "block" }}
569
- />
570
- <button
571
- onClick={() => removeImage(i)}
572
- style={{
573
- position: "absolute", top: -4, right: -4,
574
- width: 16, height: 16, borderRadius: "50%",
575
- background: "var(--bg-panel)", border: "1px solid var(--border)",
576
- display: "flex", alignItems: "center", justifyContent: "center",
577
- cursor: "pointer", padding: 0, color: "var(--text-muted)",
578
- }}
579
- >
580
- <svg width="8" height="8" viewBox="0 0 8 8" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
581
- <line x1="1" y1="1" x2="7" y2="7" /><line x1="7" y1="1" x2="1" y2="7" />
582
- </svg>
583
- </button>
584
- </div>
585
- ))}
586
- {attachedDocs.map((doc, i) => (
587
- <DocAttachmentPreview
588
- key={`doc-${i}`}
589
- doc={doc}
590
- onRemove={() => removeDoc(i)}
591
- />
592
- ))}
593
- </div>
594
- )}
595
-
596
- {/* Main input */}
597
- <div
598
- style={{
599
- display: "flex",
600
- gap: 8,
601
- alignItems: "center",
602
- background: "var(--bg)",
603
- border: "1px solid color-mix(in srgb, var(--border) 70%, transparent)",
604
- borderRadius: 14,
605
- padding: "10px 10px 10px 14px",
606
- boxShadow: "0 1px 2px rgba(15,23,42,0.04), 0 8px 24px -12px rgba(15,23,42,0.10)",
607
- transition: "border-color 0.15s, background 0.15s, box-shadow 0.15s",
608
- } as React.CSSProperties}
609
- >
610
- <textarea
611
- ref={textareaRef}
612
- value={value}
613
- onChange={(e) => setValue(e.target.value)}
614
- onKeyDown={handleKeyDown}
615
- onInput={handleInput}
616
- onPaste={handlePaste}
617
- placeholder={
618
- isStreaming ? "Agent is running…"
619
- : "Message…"
620
- }
621
- rows={1}
622
- style={{
623
- flex: 1,
624
- background: "none",
625
- border: "none",
626
- outline: "none",
627
- resize: "none",
628
- color: "var(--text)",
629
- fontSize: 14,
630
- lineHeight: 1.6,
631
- fontFamily: "inherit",
632
- minHeight: 24,
633
- maxHeight: 200,
634
- overflow: "auto",
635
- }}
636
- />
637
-
638
- {!isStreaming && (
639
- <button
640
- onClick={handleSend}
641
- disabled={!value.trim() && !attachedImages.length && !attachedDocs.length}
642
- style={{
643
- flexShrink: 0,
644
- alignSelf: "flex-end",
645
- display: "flex", alignItems: "center", gap: 6,
646
- padding: "7px 14px",
647
- background: (value.trim() || attachedImages.length || attachedDocs.length) ? "var(--accent)" : "var(--bg-panel)",
648
- border: "none",
649
- borderRadius: 8,
650
- color: (value.trim() || attachedImages.length || attachedDocs.length) ? "#fff" : "var(--text-dim)",
651
- cursor: (value.trim() || attachedImages.length || attachedDocs.length) ? "pointer" : "not-allowed",
652
- fontSize: 13,
653
- fontWeight: 600,
654
- letterSpacing: "-0.01em",
655
- boxShadow: (value.trim() || attachedImages.length || attachedDocs.length) ? "0 1px 3px rgba(37,99,235,0.25)" : "none",
656
- transition: "background 0.15s, box-shadow 0.15s",
657
- }}
658
- >
659
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
660
- <line x1="2" y1="7" x2="11" y2="7" />
661
- <polyline points="7.5 3 12 7 7.5 11" />
662
- </svg>
663
- Send
664
- </button>
665
- )}
666
- </div>
667
-
668
- {/* Bottom bar: left | center (context) | right */}
669
- <div className="chat-input-toolbar" style={{ marginTop: 8, display: "flex", alignItems: "center", gap: 6 }}>
670
-
671
- {/* LEFT: attach + model selector */}
672
- <div className="chat-input-toolbar-left" style={{ flex: "0 0 auto", display: "flex", alignItems: "center", gap: 2 }}>
673
- <button
674
- onClick={() => fileInputRef.current?.click()}
675
- disabled={isStreaming}
676
- title="Attach image (right-click for document)"
677
- style={{
678
- flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center",
679
- width: 32, height: 32, padding: 0,
680
- background: "none", border: "none",
681
- borderRadius: 9,
682
- color: attachedImages.length || attachedDocs.length ? "var(--accent)" : "var(--text-muted)",
683
- cursor: isStreaming ? "not-allowed" : "pointer",
684
- opacity: isStreaming ? 0.5 : 1,
685
- transition: "background 0.12s, color 0.12s",
686
- }}
687
- onMouseEnter={(e) => {
688
- if (isStreaming) return;
689
- e.currentTarget.style.background = "var(--bg-hover)";
690
- e.currentTarget.style.color = attachedImages.length || attachedDocs.length ? "var(--accent)" : "var(--text)";
691
- }}
692
- onMouseLeave={(e) => {
693
- e.currentTarget.style.background = "none";
694
- e.currentTarget.style.color = attachedImages.length || attachedDocs.length ? "var(--accent)" : "var(--text-muted)";
695
- }}
696
- onContextMenu={(e) => {
697
- e.preventDefault();
698
- docInputRef.current?.click();
699
- }}
700
- >
701
- <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
702
- <path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" />
703
- </svg>
704
- </button>
705
- {/* Model selector — visible always, disabled during streaming */}
706
- {modelOptions.length > 0 && onModelChange && (
707
- <div ref={dropdownRef} style={{ position: "relative" }}>
708
- <button
709
- onClick={(e) => {
710
- const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
711
- setModelDropdownRect({ top: rect.top, left: rect.left, width: rect.width });
712
- setModelDropdownOpen((v) => !v);
713
- }}
714
- disabled={isStreaming}
715
- style={{
716
- display: "flex", alignItems: "center", gap: 6,
717
- padding: "8px 12px",
718
- height: 32,
719
- maxWidth: 220, overflow: "hidden",
720
- background: modelDropdownOpen ? "var(--bg-hover)" : "none",
721
- border: "none",
722
- borderRadius: 9,
723
- color: "var(--text-muted)",
724
- cursor: isStreaming ? "not-allowed" : "pointer",
725
- fontSize: 12,
726
- opacity: isStreaming ? 0.5 : 1,
727
- transition: "background 0.12s, color 0.12s",
728
- }}
729
- onMouseEnter={(e) => {
730
- if (isStreaming) return;
731
- e.currentTarget.style.background = "var(--bg-hover)";
732
- e.currentTarget.style.color = "var(--text)";
733
- }}
734
- onMouseLeave={(e) => {
735
- e.currentTarget.style.background = modelDropdownOpen ? "var(--bg-hover)" : "none";
736
- e.currentTarget.style.color = "var(--text-muted)";
737
- }}
738
- >
739
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
740
- <rect x="4" y="4" width="16" height="16" rx="2" />
741
- <rect x="9" y="9" width="6" height="6" />
742
- <line x1="9" y1="1" x2="9" y2="4" /><line x1="15" y1="1" x2="15" y2="4" />
743
- <line x1="9" y1="20" x2="9" y2="23" /><line x1="15" y1="20" x2="15" y2="23" />
744
- <line x1="20" y1="9" x2="23" y2="9" /><line x1="20" y1="14" x2="23" y2="14" />
745
- <line x1="1" y1="9" x2="4" y2="9" /><line x1="1" y1="14" x2="4" y2="14" />
746
- </svg>
747
- <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 }}>{currentName}</span>
748
- </button>
749
- {modelDropdownOpen && modelDropdownRect && (() => {
750
- const viewportHeight = window.visualViewport?.height ?? window.innerHeight;
751
- const bottom = viewportHeight - modelDropdownRect.top + 6;
752
- const maxH = Math.max(120, Math.min(modelDropdownRect.top - 8, viewportHeight * 0.6));
753
- return (
754
- <div ref={modelDropdownPanelRef} style={{
755
- position: "fixed",
756
- bottom, left: modelDropdownRect.left,
757
- zIndex: 500, background: "var(--bg)", border: "1px solid var(--border)",
758
- borderRadius: 8, boxShadow: "0 -4px 16px rgba(0,0,0,0.10)",
759
- overflow: "hidden", width: "max-content", minWidth: modelDropdownRect.width, maxHeight: maxH, overflowY: "auto",
760
- }}>
761
- {modelsByProvider.map((group, gi) => (
762
- <div key={group.provider}>
763
- {(modelsByProvider.length > 1) && (
764
- <div style={{
765
- padding: "6px 12px 4px",
766
- fontSize: 10, fontWeight: 600, color: "var(--text-dim)",
767
- textTransform: "uppercase", letterSpacing: "0.07em",
768
- borderTop: gi > 0 ? "1px solid var(--border)" : "none",
769
- }}>
770
- {group.provider}
771
- </div>
772
- )}
773
- {group.options.map((opt) => {
774
- const isActive = opt.modelId === model?.modelId && opt.provider === model?.provider;
775
- return (
776
- <button
777
- key={`${opt.provider}:${opt.modelId}`}
778
- onClick={() => { setModelDropdownOpen(false); if (!isActive) onModelChange(opt.provider, opt.modelId); }}
779
- style={{
780
- display: "flex", alignItems: "center", gap: 8,
781
- width: "100%", padding: "7px 12px",
782
- background: isActive ? "var(--bg-selected)" : "none",
783
- border: "none",
784
- color: isActive ? "var(--text)" : "var(--text-muted)",
785
- cursor: "pointer", fontSize: 12, textAlign: "left",
786
- fontWeight: isActive ? 600 : 400,
787
- whiteSpace: "nowrap",
788
- }}
789
- onMouseEnter={(e) => { if (!isActive) e.currentTarget.style.background = "var(--bg-hover)"; }}
790
- onMouseLeave={(e) => { if (!isActive) e.currentTarget.style.background = "none"; }}
791
- >
792
- {isActive
793
- ? <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="var(--accent)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><polyline points="1.5 5 4 7.5 8.5 2.5" /></svg>
794
- : <span style={{ width: 10, flexShrink: 0 }} />}
795
- {opt.name}
796
- </button>
797
- );
798
- })}
799
- </div>
800
- ))}
801
- </div>
802
- );
803
- })()}
804
- </div>
805
- )}
806
- </div>
807
-
808
- {/* spacer */}
809
- <div className="chat-input-toolbar-spacer" style={{ flex: 1 }} />
810
-
811
- {/* RIGHT: thinking + tools preset + compact + sound (idle) | Stop + sound (streaming) */}
812
- <div className="chat-input-toolbar-right" style={{ flex: "0 0 auto", display: "flex", alignItems: "center", gap: 2, marginLeft: "auto" }}>
813
- {!isStreaming && onThinkingLevelChange && (
814
- <div ref={thinkingDropdownRef} style={{ position: "relative" }}>
815
- <button
816
- onClick={() => !isStreaming && setThinkingDropdownOpen((v) => !v)}
817
- disabled={isStreaming}
818
- title="切换推理强度"
819
- style={{
820
- display: "flex", alignItems: "center", gap: 5,
821
- padding: "8px 12px",
822
- height: 32,
823
- background: thinkingDropdownOpen ? "var(--bg-hover)" : "none",
824
- border: "none",
825
- borderRadius: 9,
826
- color: "var(--text-muted)",
827
- cursor: isStreaming ? "not-allowed" : "pointer",
828
- fontSize: 12,
829
- opacity: isStreaming ? 0.5 : 1,
830
- transition: "background 0.12s, color 0.12s",
831
- }}
832
- onMouseEnter={(e) => {
833
- if (isStreaming) return;
834
- e.currentTarget.style.background = "var(--bg-hover)";
835
- e.currentTarget.style.color = "var(--text)";
836
- }}
837
- onMouseLeave={(e) => {
838
- e.currentTarget.style.background = thinkingDropdownOpen ? "var(--bg-hover)" : "none";
839
- e.currentTarget.style.color = "var(--text-muted)";
840
- }}
841
- >
842
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
843
- <path d="M9.5 2A5.5 5.5 0 0 0 4 7.5c0 1.7.78 3.21 2 4.21V14a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1v-2.29c1.22-1 2-2.51 2-4.21A5.5 5.5 0 0 0 9.5 2z" />
844
- <line x1="7" y1="18" x2="12" y2="18" />
845
- <line x1="8" y1="21" x2="11" y2="21" />
846
- </svg>
847
- <span>{(() => {
848
- const lvl = thinkingLevel ?? "auto";
849
- if (lvl === "auto" || !thinkingLevelMap) return lvl;
850
- const mapped = thinkingLevelMap[lvl];
851
- return mapped != null ? mapped : lvl;
852
- })()}</span>
853
- </button>
854
- {thinkingDropdownOpen && (
855
- <div style={{
856
- position: "absolute", bottom: "calc(100% + 6px)", right: 0,
857
- zIndex: 100, background: "var(--bg)", border: "1px solid var(--border)",
858
- borderRadius: 8, boxShadow: "0 -4px 16px rgba(0,0,0,0.10)",
859
- overflow: "hidden", minWidth: 180,
860
- }}>
861
- {THINKING_LEVELS.filter((lvl) => {
862
- if (!availableThinkingLevels) return true;
863
- if (lvl === "auto") return true;
864
- return availableThinkingLevels.includes(lvl);
865
- }).map((lvl) => {
866
- const isActive = (thinkingLevel ?? "auto") === lvl;
867
- const desc = THINKING_LEVEL_DESC[lvl];
868
- const mappedVal = (lvl !== "auto" && thinkingLevelMap) ? thinkingLevelMap[lvl] : undefined;
869
- const displayLabel = (mappedVal != null && mappedVal !== lvl) ? mappedVal : lvl;
870
- const showOriginal = mappedVal != null && mappedVal !== lvl;
871
- return (
872
- <button
873
- key={lvl}
874
- onClick={() => { setThinkingDropdownOpen(false); if (!isActive) onThinkingLevelChange(lvl); }}
875
- style={{
876
- display: "flex", alignItems: "center", gap: 8,
877
- width: "100%", padding: "7px 12px",
878
- background: isActive ? "var(--bg-selected)" : "none",
879
- border: "none",
880
- color: isActive ? "var(--text)" : "var(--text-muted)",
881
- cursor: "pointer", fontSize: 12, textAlign: "left",
882
- fontWeight: isActive ? 600 : 400,
883
- whiteSpace: "nowrap",
884
- }}
885
- onMouseEnter={(e) => { if (!isActive) e.currentTarget.style.background = "var(--bg-hover)"; }}
886
- onMouseLeave={(e) => { if (!isActive) e.currentTarget.style.background = "none"; }}
887
- >
888
- {isActive
889
- ? <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="var(--accent)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><polyline points="1.5 5 4 7.5 8.5 2.5" /></svg>
890
- : <span style={{ width: 10, flexShrink: 0 }} />}
891
- <span style={{ flex: 1 }}>
892
- {displayLabel}
893
- {showOriginal && <span style={{ fontSize: 10, color: "var(--text-dim)", fontFamily: "var(--font-mono)", marginLeft: 5 }}>({lvl})</span>}
894
- </span>
895
- <span style={{ fontSize: 11, color: "var(--text-dim)", marginLeft: 8 }}>{desc}</span>
896
- </button>
897
- );
898
- })}
899
- </div>
900
- )}
901
- </div>
902
- )}
903
- {!isStreaming && onToolPresetChange && (
904
- <div ref={toolDropdownRef} style={{ position: "relative" }}>
905
- <button
906
- onClick={() => !isStreaming && setToolDropdownOpen((v) => !v)}
907
- disabled={isStreaming}
908
- title="切换工具预设"
909
- style={{
910
- display: "flex", alignItems: "center", gap: 5,
911
- padding: "8px 12px",
912
- height: 32,
913
- background: toolDropdownOpen ? "var(--bg-hover)" : "none",
914
- border: "none",
915
- borderRadius: 9,
916
- color: "var(--text-muted)",
917
- cursor: isStreaming ? "not-allowed" : "pointer",
918
- fontSize: 12,
919
- opacity: isStreaming ? 0.5 : 1,
920
- transition: "background 0.12s, color 0.12s",
921
- }}
922
- onMouseEnter={(e) => {
923
- if (isStreaming) return;
924
- e.currentTarget.style.background = "var(--bg-hover)";
925
- e.currentTarget.style.color = "var(--text)";
926
- }}
927
- onMouseLeave={(e) => {
928
- e.currentTarget.style.background = toolDropdownOpen ? "var(--bg-hover)" : "none";
929
- e.currentTarget.style.color = "var(--text-muted)";
930
- }}
931
- >
932
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
933
- <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
934
- </svg>
935
- <span>{Object.entries(TOOL_PRESET_MAP).find(([, v]) => v === (toolPreset ?? "full"))?.[0] ?? "full"}</span>
936
- </button>
937
- {toolDropdownOpen && (
938
- <div style={{
939
- position: "absolute", bottom: "calc(100% + 6px)", right: 0,
940
- zIndex: 100, background: "var(--bg)", border: "1px solid var(--border)",
941
- borderRadius: 8, boxShadow: "0 -4px 16px rgba(0,0,0,0.10)",
942
- overflow: "hidden", minWidth: 120,
943
- }}>
944
- {TOOL_PRESETS.map((lvl) => {
945
- const preset = TOOL_PRESET_MAP[lvl];
946
- const isActive = (toolPreset ?? "full") === preset;
947
- const desc = lvl === "off" ? "无工具,纯聊天" : lvl === "default" ? "4 项内置工具" : "全部内置工具";
948
- return (
949
- <button
950
- key={lvl}
951
- onClick={() => { setToolDropdownOpen(false); if (!isActive) onToolPresetChange(preset); }}
952
- style={{
953
- display: "flex", alignItems: "center", gap: 8,
954
- width: "100%", padding: "7px 12px",
955
- background: isActive ? "var(--bg-selected)" : "none",
956
- border: "none",
957
- color: isActive ? "var(--text)" : "var(--text-muted)",
958
- cursor: "pointer", fontSize: 12, textAlign: "left",
959
- fontWeight: isActive ? 600 : 400,
960
- whiteSpace: "nowrap",
961
- }}
962
- onMouseEnter={(e) => { if (!isActive) e.currentTarget.style.background = "var(--bg-hover)"; }}
963
- onMouseLeave={(e) => { if (!isActive) e.currentTarget.style.background = "none"; }}
964
- >
965
- {isActive
966
- ? <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="var(--accent)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><polyline points="1.5 5 4 7.5 8.5 2.5" /></svg>
967
- : <span style={{ width: 10, flexShrink: 0 }} />}
968
- <span style={{ flex: 1 }}>{lvl}</span>
969
- <span style={{ fontSize: 11, color: "var(--text-dim)", marginLeft: 8 }}>{desc}</span>
970
- </button>
971
- );
972
- })}
973
- </div>
974
- )}
975
- </div>
976
- )}
977
-
978
- {!isStreaming && onCompact && (
979
- <div style={{ position: "relative" }}>
980
- {compactError && (
981
- <div style={{
982
- position: "absolute", bottom: "calc(100% + 6px)", right: 0,
983
- background: "#1f2937", color: "#f87171",
984
- fontSize: 11, padding: "4px 8px", borderRadius: 5,
985
- whiteSpace: "nowrap", pointerEvents: "none",
986
- boxShadow: "0 2px 8px rgba(0,0,0,0.2)", zIndex: 50,
987
- }}>
988
- {compactError}
989
- </div>
990
- )}
991
- <button
992
- onClick={isCompacting ? onAbortCompaction : onCompact}
993
- disabled={isStreaming && !isCompacting}
994
- style={{
995
- display: "flex", alignItems: "center", gap: 5,
996
- padding: "8px 12px",
997
- height: 32,
998
- background: isCompacting ? "rgba(239,68,68,0.08)" : "none",
999
- border: "none",
1000
- borderRadius: 9,
1001
- color: isCompacting ? "#ef4444" : "var(--text-muted)",
1002
- cursor: (isStreaming && !isCompacting) ? "not-allowed" : "pointer",
1003
- fontSize: 12, opacity: (isStreaming && !isCompacting) ? 0.5 : 1,
1004
- transition: "background 0.12s, color 0.12s",
1005
- }}
1006
- onMouseEnter={(e) => {
1007
- if (isStreaming && !isCompacting) return;
1008
- e.currentTarget.style.background = isCompacting ? "rgba(239,68,68,0.16)" : "var(--bg-hover)";
1009
- e.currentTarget.style.color = isCompacting ? "#ef4444" : "var(--text)";
1010
- }}
1011
- onMouseLeave={(e) => {
1012
- e.currentTarget.style.background = isCompacting ? "rgba(239,68,68,0.08)" : "none";
1013
- e.currentTarget.style.color = isCompacting ? "#ef4444" : "var(--text-muted)";
1014
- }}
1015
- title={isCompacting ? "停止压缩" : "压缩上下文"}
1016
- >
1017
- {isCompacting ? (
1018
- <><svg width="10" height="10" viewBox="0 0 10 10" fill="none"><rect x="2" y="2" width="6" height="6" rx="1" fill="currentColor" /></svg>Compacting…</>
1019
- ) : (
1020
- <><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1021
- <polyline points="4 14 10 14 10 20" /><polyline points="20 10 14 10 14 4" />
1022
- <line x1="10" y1="14" x2="3" y2="21" /><line x1="21" y1="3" x2="14" y2="10" />
1023
- </svg>Compact</>
1024
- )}
1025
- </button>
1026
- </div>
1027
- )}
1028
-
1029
- {isStreaming && (
1030
- <button
1031
- onClick={onAbort}
1032
- title="停止 Agent"
1033
- style={{
1034
- display: "flex", alignItems: "center", gap: 6,
1035
- padding: "8px 14px",
1036
- height: 32,
1037
- background: "rgba(239,68,68,0.08)",
1038
- border: "1px solid rgba(239,68,68,0.3)",
1039
- borderRadius: 9,
1040
- color: "#ef4444",
1041
- cursor: "pointer",
1042
- fontSize: 12, fontWeight: 600,
1043
- whiteSpace: "nowrap", letterSpacing: "-0.01em",
1044
- transition: "background 0.12s",
1045
- }}
1046
- onMouseEnter={(e) => { e.currentTarget.style.background = "rgba(239,68,68,0.16)"; }}
1047
- onMouseLeave={(e) => { e.currentTarget.style.background = "rgba(239,68,68,0.08)"; }}
1048
- >
1049
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
1050
- <rect x="1.5" y="1.5" width="7" height="7" rx="1.5" fill="currentColor" />
1051
- </svg>
1052
- Stop
1053
- </button>
1054
- )}
1055
-
1056
- {onSoundToggle !== undefined && (
1057
- <button
1058
- onClick={onSoundToggle}
1059
- title={soundEnabled ? "关闭完成提示音" : "开启完成提示音"}
1060
- style={{
1061
- display: "flex", alignItems: "center", justifyContent: "center",
1062
- width: 32, height: 32, padding: 0,
1063
- background: "none",
1064
- border: "none",
1065
- borderRadius: 9,
1066
- color: soundEnabled ? "var(--text-muted)" : "var(--text-dim)",
1067
- cursor: "pointer",
1068
- opacity: soundEnabled ? 1 : 0.55,
1069
- transition: "background 0.12s, color 0.12s, opacity 0.12s",
1070
- }}
1071
- onMouseEnter={(e) => {
1072
- e.currentTarget.style.background = "var(--bg-hover)";
1073
- e.currentTarget.style.color = "var(--text)";
1074
- e.currentTarget.style.opacity = "1";
1075
- }}
1076
- onMouseLeave={(e) => {
1077
- e.currentTarget.style.background = "none";
1078
- e.currentTarget.style.color = soundEnabled ? "var(--text-muted)" : "var(--text-dim)";
1079
- e.currentTarget.style.opacity = soundEnabled ? "1" : "0.55";
1080
- }}
1081
- >
1082
- {soundEnabled ? (
1083
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1084
- <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
1085
- <path d="M15.54 8.46a5 5 0 0 1 0 7.07" />
1086
- <path d="M19.07 4.93a10 10 0 0 1 0 14.14" />
1087
- </svg>
1088
- ) : (
1089
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
1090
- <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
1091
- <line x1="23" y1="9" x2="17" y2="15" />
1092
- <line x1="17" y1="9" x2="23" y2="15" />
1093
- </svg>
1094
- )}
1095
- </button>
1096
- )}
1097
- </div>
1098
-
1099
- </div>
1100
- </div>
1101
- </div>
1102
- );
1103
- });