@adea-ai/ui 0.140.0 → 0.142.0

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 (455) hide show
  1. package/dist/components/composites/appearance-editor/appearance-editor.js +2 -2
  2. package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
  3. package/dist/components/composites/catalog-browser/catalog-browser-group.js +1 -1
  4. package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts +56 -0
  5. package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts.map +1 -0
  6. package/dist/components/composites/chain-of-thought/chain-of-thought.js +117 -0
  7. package/dist/components/composites/chain-of-thought/chain-of-thought.js.map +1 -0
  8. package/dist/components/composites/chain-of-thought/index.d.ts +2 -0
  9. package/dist/components/composites/chain-of-thought/index.d.ts.map +1 -0
  10. package/dist/components/composites/chain-of-thought/index.js +2 -0
  11. package/dist/components/composites/chat/chat.d.ts +67 -0
  12. package/dist/components/composites/chat/chat.d.ts.map +1 -0
  13. package/dist/components/composites/chat/chat.js +179 -0
  14. package/dist/components/composites/chat/chat.js.map +1 -0
  15. package/dist/components/composites/chat/index.d.ts +2 -0
  16. package/dist/components/composites/chat/index.d.ts.map +1 -0
  17. package/dist/components/composites/chat/index.js +2 -0
  18. package/dist/components/composites/checkpoint/checkpoint-model.d.ts +34 -0
  19. package/dist/components/composites/checkpoint/checkpoint-model.d.ts.map +1 -0
  20. package/dist/components/composites/checkpoint/checkpoint-model.js +48 -0
  21. package/dist/components/composites/checkpoint/checkpoint-model.js.map +1 -0
  22. package/dist/components/composites/checkpoint/checkpoint.d.ts +48 -0
  23. package/dist/components/composites/checkpoint/checkpoint.d.ts.map +1 -0
  24. package/dist/components/composites/checkpoint/checkpoint.js +160 -0
  25. package/dist/components/composites/checkpoint/checkpoint.js.map +1 -0
  26. package/dist/components/composites/checkpoint/index.d.ts +3 -0
  27. package/dist/components/composites/checkpoint/index.d.ts.map +1 -0
  28. package/dist/components/composites/checkpoint/index.js +3 -0
  29. package/dist/components/composites/confirmation/confirmation-model.d.ts +45 -0
  30. package/dist/components/composites/confirmation/confirmation-model.d.ts.map +1 -0
  31. package/dist/components/composites/confirmation/confirmation-model.js +51 -0
  32. package/dist/components/composites/confirmation/confirmation-model.js.map +1 -0
  33. package/dist/components/composites/confirmation/confirmation.d.ts +72 -0
  34. package/dist/components/composites/confirmation/confirmation.d.ts.map +1 -0
  35. package/dist/components/composites/confirmation/confirmation.js +300 -0
  36. package/dist/components/composites/confirmation/confirmation.js.map +1 -0
  37. package/dist/components/composites/confirmation/index.d.ts +3 -0
  38. package/dist/components/composites/confirmation/index.d.ts.map +1 -0
  39. package/dist/components/composites/confirmation/index.js +3 -0
  40. package/dist/components/composites/context/context-model.d.ts +69 -0
  41. package/dist/components/composites/context/context-model.d.ts.map +1 -0
  42. package/dist/components/composites/context/context-model.js +122 -0
  43. package/dist/components/composites/context/context-model.js.map +1 -0
  44. package/dist/components/composites/context/context.d.ts +38 -0
  45. package/dist/components/composites/context/context.d.ts.map +1 -0
  46. package/dist/components/composites/context/context.js +234 -0
  47. package/dist/components/composites/context/context.js.map +1 -0
  48. package/dist/components/composites/context/index.d.ts +3 -0
  49. package/dist/components/composites/context/index.d.ts.map +1 -0
  50. package/dist/components/composites/context/index.js +3 -0
  51. package/dist/components/composites/file-tree/build-file-tree.d.ts +138 -0
  52. package/dist/components/composites/file-tree/build-file-tree.d.ts.map +1 -0
  53. package/dist/components/composites/file-tree/build-file-tree.js +325 -0
  54. package/dist/components/composites/file-tree/build-file-tree.js.map +1 -0
  55. package/dist/components/composites/file-tree/file-tree.d.ts +74 -0
  56. package/dist/components/composites/file-tree/file-tree.d.ts.map +1 -0
  57. package/dist/components/composites/file-tree/file-tree.js +389 -0
  58. package/dist/components/composites/file-tree/file-tree.js.map +1 -0
  59. package/dist/components/composites/file-tree/index.d.ts +3 -0
  60. package/dist/components/composites/file-tree/index.d.ts.map +1 -0
  61. package/dist/components/composites/file-tree/index.js +3 -0
  62. package/dist/components/composites/inline-citation/citation.d.ts +37 -0
  63. package/dist/components/composites/inline-citation/citation.d.ts.map +1 -0
  64. package/dist/components/composites/inline-citation/citation.js +52 -0
  65. package/dist/components/composites/inline-citation/citation.js.map +1 -0
  66. package/dist/components/composites/inline-citation/index.d.ts +3 -0
  67. package/dist/components/composites/inline-citation/index.d.ts.map +1 -0
  68. package/dist/components/composites/inline-citation/index.js +3 -0
  69. package/dist/components/composites/inline-citation/inline-citation.d.ts +64 -0
  70. package/dist/components/composites/inline-citation/inline-citation.d.ts.map +1 -0
  71. package/dist/components/composites/inline-citation/inline-citation.js +272 -0
  72. package/dist/components/composites/inline-citation/inline-citation.js.map +1 -0
  73. package/dist/components/composites/message-scroller/index.d.ts +3 -0
  74. package/dist/components/composites/message-scroller/index.d.ts.map +1 -0
  75. package/dist/components/composites/message-scroller/index.js +3 -0
  76. package/dist/components/composites/message-scroller/message-scroller.d.ts +55 -0
  77. package/dist/components/composites/message-scroller/message-scroller.d.ts.map +1 -0
  78. package/dist/components/composites/message-scroller/message-scroller.js +201 -0
  79. package/dist/components/composites/message-scroller/message-scroller.js.map +1 -0
  80. package/dist/components/composites/message-scroller/scroll-anchor.d.ts +66 -0
  81. package/dist/components/composites/message-scroller/scroll-anchor.d.ts.map +1 -0
  82. package/dist/components/composites/message-scroller/scroll-anchor.js +122 -0
  83. package/dist/components/composites/message-scroller/scroll-anchor.js.map +1 -0
  84. package/dist/components/composites/model-selector/index.d.ts +3 -0
  85. package/dist/components/composites/model-selector/index.d.ts.map +1 -0
  86. package/dist/components/composites/model-selector/index.js +3 -0
  87. package/dist/components/composites/model-selector/model-selector.d.ts +55 -0
  88. package/dist/components/composites/model-selector/model-selector.d.ts.map +1 -0
  89. package/dist/components/composites/model-selector/model-selector.js +490 -0
  90. package/dist/components/composites/model-selector/model-selector.js.map +1 -0
  91. package/dist/components/composites/model-selector/models.d.ts +51 -0
  92. package/dist/components/composites/model-selector/models.d.ts.map +1 -0
  93. package/dist/components/composites/model-selector/models.js +71 -0
  94. package/dist/components/composites/model-selector/models.js.map +1 -0
  95. package/dist/components/composites/plan/index.d.ts +2 -0
  96. package/dist/components/composites/plan/index.d.ts.map +1 -0
  97. package/dist/components/composites/plan/index.js +2 -0
  98. package/dist/components/composites/plan/plan.d.ts +61 -0
  99. package/dist/components/composites/plan/plan.d.ts.map +1 -0
  100. package/dist/components/composites/plan/plan.js +130 -0
  101. package/dist/components/composites/plan/plan.js.map +1 -0
  102. package/dist/components/composites/queue/index.d.ts +2 -0
  103. package/dist/components/composites/queue/index.d.ts.map +1 -0
  104. package/dist/components/composites/queue/index.js +2 -0
  105. package/dist/components/composites/queue/queue.d.ts +77 -0
  106. package/dist/components/composites/queue/queue.d.ts.map +1 -0
  107. package/dist/components/composites/queue/queue.js +271 -0
  108. package/dist/components/composites/queue/queue.js.map +1 -0
  109. package/dist/components/composites/reasoning/index.d.ts +2 -0
  110. package/dist/components/composites/reasoning/index.d.ts.map +1 -0
  111. package/dist/components/composites/reasoning/index.js +2 -0
  112. package/dist/components/composites/reasoning/reasoning.d.ts +62 -0
  113. package/dist/components/composites/reasoning/reasoning.d.ts.map +1 -0
  114. package/dist/components/composites/reasoning/reasoning.js +156 -0
  115. package/dist/components/composites/reasoning/reasoning.js.map +1 -0
  116. package/dist/components/composites/sources/index.d.ts +3 -0
  117. package/dist/components/composites/sources/index.d.ts.map +1 -0
  118. package/dist/components/composites/sources/index.js +3 -0
  119. package/dist/components/composites/sources/source.d.ts +46 -0
  120. package/dist/components/composites/sources/source.d.ts.map +1 -0
  121. package/dist/components/composites/sources/source.js +74 -0
  122. package/dist/components/composites/sources/source.js.map +1 -0
  123. package/dist/components/composites/sources/sources.d.ts +45 -0
  124. package/dist/components/composites/sources/sources.d.ts.map +1 -0
  125. package/dist/components/composites/sources/sources.js +175 -0
  126. package/dist/components/composites/sources/sources.js.map +1 -0
  127. package/dist/components/composites/stack-trace/index.d.ts +3 -0
  128. package/dist/components/composites/stack-trace/index.d.ts.map +1 -0
  129. package/dist/components/composites/stack-trace/index.js +3 -0
  130. package/dist/components/composites/stack-trace/parse-stack-trace.d.ts +118 -0
  131. package/dist/components/composites/stack-trace/parse-stack-trace.d.ts.map +1 -0
  132. package/dist/components/composites/stack-trace/parse-stack-trace.js +376 -0
  133. package/dist/components/composites/stack-trace/parse-stack-trace.js.map +1 -0
  134. package/dist/components/composites/stack-trace/stack-trace.d.ts +63 -0
  135. package/dist/components/composites/stack-trace/stack-trace.d.ts.map +1 -0
  136. package/dist/components/composites/stack-trace/stack-trace.js +491 -0
  137. package/dist/components/composites/stack-trace/stack-trace.js.map +1 -0
  138. package/dist/components/composites/subagent/index.d.ts +2 -0
  139. package/dist/components/composites/subagent/index.d.ts.map +1 -0
  140. package/dist/components/composites/subagent/index.js +2 -0
  141. package/dist/components/composites/subagent/subagent.d.ts +55 -0
  142. package/dist/components/composites/subagent/subagent.d.ts.map +1 -0
  143. package/dist/components/composites/subagent/subagent.js +138 -0
  144. package/dist/components/composites/subagent/subagent.js.map +1 -0
  145. package/dist/components/composites/suggestion/index.d.ts +2 -0
  146. package/dist/components/composites/suggestion/index.d.ts.map +1 -0
  147. package/dist/components/composites/suggestion/index.js +2 -0
  148. package/dist/components/composites/suggestion/suggestion.d.ts +37 -0
  149. package/dist/components/composites/suggestion/suggestion.d.ts.map +1 -0
  150. package/dist/components/composites/suggestion/suggestion.js +100 -0
  151. package/dist/components/composites/suggestion/suggestion.js.map +1 -0
  152. package/dist/components/composites/task/index.d.ts +2 -0
  153. package/dist/components/composites/task/index.d.ts.map +1 -0
  154. package/dist/components/composites/task/index.js +2 -0
  155. package/dist/components/composites/task/task.d.ts +96 -0
  156. package/dist/components/composites/task/task.d.ts.map +1 -0
  157. package/dist/components/composites/task/task.js +311 -0
  158. package/dist/components/composites/task/task.js.map +1 -0
  159. package/dist/components/composites/terminal/ansi.d.ts +101 -0
  160. package/dist/components/composites/terminal/ansi.d.ts.map +1 -0
  161. package/dist/components/composites/terminal/ansi.js +544 -0
  162. package/dist/components/composites/terminal/ansi.js.map +1 -0
  163. package/dist/components/composites/terminal/index.d.ts +4 -0
  164. package/dist/components/composites/terminal/index.d.ts.map +1 -0
  165. package/dist/components/composites/terminal/index.js +4 -0
  166. package/dist/components/composites/terminal/terminal-model.d.ts +63 -0
  167. package/dist/components/composites/terminal/terminal-model.d.ts.map +1 -0
  168. package/dist/components/composites/terminal/terminal-model.js +69 -0
  169. package/dist/components/composites/terminal/terminal-model.js.map +1 -0
  170. package/dist/components/composites/terminal/terminal.d.ts +88 -0
  171. package/dist/components/composites/terminal/terminal.d.ts.map +1 -0
  172. package/dist/components/composites/terminal/terminal.js +500 -0
  173. package/dist/components/composites/terminal/terminal.js.map +1 -0
  174. package/dist/components/composites/test-results/index.d.ts +3 -0
  175. package/dist/components/composites/test-results/index.d.ts.map +1 -0
  176. package/dist/components/composites/test-results/index.js +3 -0
  177. package/dist/components/composites/test-results/test-results-model.d.ts +154 -0
  178. package/dist/components/composites/test-results/test-results-model.d.ts.map +1 -0
  179. package/dist/components/composites/test-results/test-results-model.js +252 -0
  180. package/dist/components/composites/test-results/test-results-model.js.map +1 -0
  181. package/dist/components/composites/test-results/test-results.d.ts +60 -0
  182. package/dist/components/composites/test-results/test-results.d.ts.map +1 -0
  183. package/dist/components/composites/test-results/test-results.js +631 -0
  184. package/dist/components/composites/test-results/test-results.js.map +1 -0
  185. package/dist/components/composites/tool/format-tool-value.d.ts +37 -0
  186. package/dist/components/composites/tool/format-tool-value.d.ts.map +1 -0
  187. package/dist/components/composites/tool/format-tool-value.js +135 -0
  188. package/dist/components/composites/tool/format-tool-value.js.map +1 -0
  189. package/dist/components/composites/tool/index.d.ts +3 -0
  190. package/dist/components/composites/tool/index.d.ts.map +1 -0
  191. package/dist/components/composites/tool/index.js +3 -0
  192. package/dist/components/composites/tool/tool.d.ts +69 -0
  193. package/dist/components/composites/tool/tool.d.ts.map +1 -0
  194. package/dist/components/composites/tool/tool.js +214 -0
  195. package/dist/components/composites/tool/tool.js.map +1 -0
  196. package/dist/components/composites/update-dialog/update-dialog.js +1 -1
  197. package/dist/components/conversation/conversation-surface.d.ts +7 -0
  198. package/dist/components/conversation/conversation-surface.d.ts.map +1 -1
  199. package/dist/components/conversation/conversation-surface.js +2 -0
  200. package/dist/components/conversation/conversation-surface.js.map +1 -1
  201. package/dist/components/conversation/scroll-follow-core.d.ts +24 -0
  202. package/dist/components/conversation/scroll-follow-core.d.ts.map +1 -1
  203. package/dist/components/conversation/scroll-follow-core.js +23 -1
  204. package/dist/components/conversation/scroll-follow-core.js.map +1 -1
  205. package/dist/components/conversation/scroll-follow.d.ts +3 -0
  206. package/dist/components/conversation/scroll-follow.d.ts.map +1 -1
  207. package/dist/components/conversation/scroll-follow.js +80 -1
  208. package/dist/components/conversation/scroll-follow.js.map +1 -1
  209. package/dist/components/ui/attachment/attachment.d.ts +58 -0
  210. package/dist/components/ui/attachment/attachment.d.ts.map +1 -0
  211. package/dist/components/ui/attachment/attachment.js +279 -0
  212. package/dist/components/ui/attachment/attachment.js.map +1 -0
  213. package/dist/components/ui/attachment/index.d.ts +2 -0
  214. package/dist/components/ui/attachment/index.d.ts.map +1 -0
  215. package/dist/components/ui/attachment/index.js +2 -0
  216. package/dist/components/ui/badge/badge.d.ts +1 -1
  217. package/dist/components/ui/bubble/bubble.d.ts +33 -0
  218. package/dist/components/ui/bubble/bubble.d.ts.map +1 -0
  219. package/dist/components/ui/bubble/bubble.js +95 -0
  220. package/dist/components/ui/bubble/bubble.js.map +1 -0
  221. package/dist/components/ui/bubble/index.d.ts +2 -0
  222. package/dist/components/ui/bubble/index.d.ts.map +1 -0
  223. package/dist/components/ui/bubble/index.js +2 -0
  224. package/dist/components/ui/button/button.d.ts +1 -1
  225. package/dist/components/ui/code-block/code-block.d.ts +56 -3
  226. package/dist/components/ui/code-block/code-block.d.ts.map +1 -1
  227. package/dist/components/ui/code-block/code-block.js +231 -50
  228. package/dist/components/ui/code-block/code-block.js.map +1 -1
  229. package/dist/components/ui/code-block/index.d.ts +1 -1
  230. package/dist/components/ui/code-block/index.d.ts.map +1 -1
  231. package/dist/components/ui/code-block/index.js +2 -2
  232. package/dist/components/ui/field/number-field.d.ts +21 -4
  233. package/dist/components/ui/field/number-field.d.ts.map +1 -1
  234. package/dist/components/ui/field/number-field.js +22 -11
  235. package/dist/components/ui/field/number-field.js.map +1 -1
  236. package/dist/components/ui/marker/index.d.ts +2 -0
  237. package/dist/components/ui/marker/index.d.ts.map +1 -0
  238. package/dist/components/ui/marker/index.js +2 -0
  239. package/dist/components/ui/marker/marker.d.ts +35 -0
  240. package/dist/components/ui/marker/marker.d.ts.map +1 -0
  241. package/dist/components/ui/marker/marker.js +123 -0
  242. package/dist/components/ui/marker/marker.js.map +1 -0
  243. package/dist/components/ui/message/cite-ranges.d.ts +42 -0
  244. package/dist/components/ui/message/cite-ranges.d.ts.map +1 -0
  245. package/dist/components/ui/message/cite-ranges.js +105 -0
  246. package/dist/components/ui/message/cite-ranges.js.map +1 -0
  247. package/dist/components/ui/message/index.d.ts +4 -0
  248. package/dist/components/ui/message/index.d.ts.map +1 -0
  249. package/dist/components/ui/message/index.js +4 -0
  250. package/dist/components/ui/message/message.d.ts +95 -0
  251. package/dist/components/ui/message/message.d.ts.map +1 -0
  252. package/dist/components/ui/message/message.js +443 -0
  253. package/dist/components/ui/message/message.js.map +1 -0
  254. package/dist/components/ui/message/parse-message-text.d.ts +93 -0
  255. package/dist/components/ui/message/parse-message-text.d.ts.map +1 -0
  256. package/dist/components/ui/message/parse-message-text.js +365 -0
  257. package/dist/components/ui/message/parse-message-text.js.map +1 -0
  258. package/dist/components/ui/questionnaire/index.d.ts +2 -0
  259. package/dist/components/ui/questionnaire/index.d.ts.map +1 -0
  260. package/dist/components/ui/questionnaire/index.js +2 -0
  261. package/dist/components/ui/questionnaire/questionnaire.d.ts +83 -0
  262. package/dist/components/ui/questionnaire/questionnaire.d.ts.map +1 -0
  263. package/dist/components/ui/questionnaire/questionnaire.js +470 -0
  264. package/dist/components/ui/questionnaire/questionnaire.js.map +1 -0
  265. package/dist/components/ui/status-chip/status-chip.d.ts +1 -1
  266. package/dist/components/ui/switch/switch.js +11 -11
  267. package/dist/components/ui/switch/switch.js.map +1 -1
  268. package/dist/components/ui/trace/index.d.ts +2 -0
  269. package/dist/components/ui/trace/index.d.ts.map +1 -0
  270. package/dist/components/ui/trace/index.js +2 -0
  271. package/dist/components/ui/trace/trace.d.ts +72 -0
  272. package/dist/components/ui/trace/trace.d.ts.map +1 -0
  273. package/dist/components/ui/trace/trace.js +340 -0
  274. package/dist/components/ui/trace/trace.js.map +1 -0
  275. package/dist/index.d.ts +26 -0
  276. package/dist/index.d.ts.map +1 -1
  277. package/dist/index.js +46 -5
  278. package/dist/r/attachment.json +25 -0
  279. package/dist/r/bubble.json +22 -0
  280. package/dist/r/chain-of-thought.json +26 -0
  281. package/dist/r/chat.json +24 -0
  282. package/dist/r/checkpoint.json +35 -0
  283. package/dist/r/confirmation.json +34 -0
  284. package/dist/r/context.json +33 -0
  285. package/dist/r/file-tree.json +32 -0
  286. package/dist/r/inline-citation.json +35 -0
  287. package/dist/r/marker.json +22 -0
  288. package/dist/r/message-scroller.json +31 -0
  289. package/dist/r/message.json +33 -0
  290. package/dist/r/model-selector.json +34 -0
  291. package/dist/r/plan.json +26 -0
  292. package/dist/r/questionnaire.json +28 -0
  293. package/dist/r/queue.json +26 -0
  294. package/dist/r/reasoning.json +26 -0
  295. package/dist/r/registry.json +811 -52
  296. package/dist/r/sources.json +32 -0
  297. package/dist/r/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
  298. package/dist/r/src/components/composites/chain-of-thought/index.ts +11 -0
  299. package/dist/r/src/components/composites/chat/chat.tsx +190 -0
  300. package/dist/r/src/components/composites/chat/index.ts +11 -0
  301. package/dist/r/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
  302. package/dist/r/src/components/composites/checkpoint/checkpoint.tsx +214 -0
  303. package/dist/r/src/components/composites/checkpoint/index.ts +8 -0
  304. package/dist/r/src/components/composites/confirmation/confirmation-model.ts +83 -0
  305. package/dist/r/src/components/composites/confirmation/confirmation.tsx +311 -0
  306. package/dist/r/src/components/composites/confirmation/index.ts +9 -0
  307. package/dist/r/src/components/composites/context/context-model.ts +168 -0
  308. package/dist/r/src/components/composites/context/context.tsx +187 -0
  309. package/dist/r/src/components/composites/context/index.ts +18 -0
  310. package/dist/r/src/components/composites/file-tree/build-file-tree.ts +456 -0
  311. package/dist/r/src/components/composites/file-tree/file-tree.tsx +405 -0
  312. package/dist/r/src/components/composites/file-tree/index.ts +25 -0
  313. package/dist/r/src/components/composites/inline-citation/citation.ts +78 -0
  314. package/dist/r/src/components/composites/inline-citation/index.ts +9 -0
  315. package/dist/r/src/components/composites/inline-citation/inline-citation.tsx +285 -0
  316. package/dist/r/src/components/composites/message-scroller/index.ts +2 -0
  317. package/dist/r/src/components/composites/message-scroller/message-scroller.tsx +301 -0
  318. package/dist/r/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
  319. package/dist/r/src/components/composites/model-selector/index.ts +14 -0
  320. package/dist/r/src/components/composites/model-selector/model-selector.tsx +420 -0
  321. package/dist/r/src/components/composites/model-selector/models.ts +103 -0
  322. package/dist/r/src/components/composites/plan/index.ts +1 -0
  323. package/dist/r/src/components/composites/plan/plan.tsx +155 -0
  324. package/dist/r/src/components/composites/queue/index.ts +10 -0
  325. package/dist/r/src/components/composites/queue/queue.tsx +264 -0
  326. package/dist/r/src/components/composites/reasoning/index.ts +1 -0
  327. package/dist/r/src/components/composites/reasoning/reasoning.tsx +176 -0
  328. package/dist/r/src/components/composites/sources/index.ts +11 -0
  329. package/dist/r/src/components/composites/sources/source.ts +116 -0
  330. package/dist/r/src/components/composites/sources/sources.tsx +163 -0
  331. package/dist/r/src/components/composites/stack-trace/index.ts +19 -0
  332. package/dist/r/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
  333. package/dist/r/src/components/composites/stack-trace/stack-trace.tsx +395 -0
  334. package/dist/r/src/components/composites/subagent/index.ts +1 -0
  335. package/dist/r/src/components/composites/subagent/subagent.tsx +159 -0
  336. package/dist/r/src/components/composites/suggestion/index.ts +1 -0
  337. package/dist/r/src/components/composites/suggestion/suggestion.tsx +140 -0
  338. package/dist/r/src/components/composites/task/index.ts +14 -0
  339. package/dist/r/src/components/composites/task/task.tsx +317 -0
  340. package/dist/r/src/components/composites/terminal/ansi.ts +674 -0
  341. package/dist/r/src/components/composites/terminal/index.ts +20 -0
  342. package/dist/r/src/components/composites/terminal/terminal-model.ts +111 -0
  343. package/dist/r/src/components/composites/terminal/terminal.tsx +574 -0
  344. package/dist/r/src/components/composites/test-results/index.ts +20 -0
  345. package/dist/r/src/components/composites/test-results/test-results-model.ts +368 -0
  346. package/dist/r/src/components/composites/test-results/test-results.tsx +586 -0
  347. package/dist/r/src/components/composites/tool/format-tool-value.ts +221 -0
  348. package/dist/r/src/components/composites/tool/index.ts +2 -0
  349. package/dist/r/src/components/composites/tool/tool.tsx +228 -0
  350. package/dist/r/src/components/conversation/conversation-surface.tsx +9 -0
  351. package/dist/r/src/components/conversation/scroll-follow-core.ts +31 -0
  352. package/dist/r/src/components/conversation/scroll-follow.ts +92 -0
  353. package/dist/r/src/components/ui/attachment/attachment.tsx +282 -0
  354. package/dist/r/src/components/ui/attachment/index.ts +10 -0
  355. package/dist/r/src/components/ui/bubble/bubble.tsx +86 -0
  356. package/dist/r/src/components/ui/bubble/index.ts +1 -0
  357. package/dist/r/src/components/ui/code-block/code-block.tsx +256 -26
  358. package/dist/r/src/components/ui/code-block/index.ts +9 -1
  359. package/dist/r/src/components/ui/field/number-field.tsx +51 -14
  360. package/dist/r/src/components/ui/marker/index.ts +1 -0
  361. package/dist/r/src/components/ui/marker/marker.tsx +90 -0
  362. package/dist/r/src/components/ui/message/cite-ranges.ts +144 -0
  363. package/dist/r/src/components/ui/message/index.ts +23 -0
  364. package/dist/r/src/components/ui/message/message.tsx +434 -0
  365. package/dist/r/src/components/ui/message/parse-message-text.ts +450 -0
  366. package/dist/r/src/components/ui/questionnaire/index.ts +10 -0
  367. package/dist/r/src/components/ui/questionnaire/questionnaire.tsx +446 -0
  368. package/dist/r/src/components/ui/trace/index.ts +9 -0
  369. package/dist/r/src/components/ui/trace/trace.tsx +334 -0
  370. package/dist/r/src/styles/base.css +34 -0
  371. package/dist/r/stack-trace.json +32 -0
  372. package/dist/r/subagent.json +27 -0
  373. package/dist/r/suggestion.json +24 -0
  374. package/dist/r/task.json +28 -0
  375. package/dist/r/terminal.json +35 -0
  376. package/dist/r/test-results.json +33 -0
  377. package/dist/r/tool.json +31 -0
  378. package/dist/r/trace.json +25 -0
  379. package/package.json +6 -3
  380. package/registry.json +811 -52
  381. package/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
  382. package/src/components/composites/chain-of-thought/index.ts +11 -0
  383. package/src/components/composites/chat/chat.tsx +190 -0
  384. package/src/components/composites/chat/index.ts +11 -0
  385. package/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
  386. package/src/components/composites/checkpoint/checkpoint.tsx +214 -0
  387. package/src/components/composites/checkpoint/index.ts +8 -0
  388. package/src/components/composites/confirmation/confirmation-model.ts +83 -0
  389. package/src/components/composites/confirmation/confirmation.tsx +311 -0
  390. package/src/components/composites/confirmation/index.ts +9 -0
  391. package/src/components/composites/context/context-model.ts +168 -0
  392. package/src/components/composites/context/context.tsx +187 -0
  393. package/src/components/composites/context/index.ts +18 -0
  394. package/src/components/composites/file-tree/build-file-tree.ts +456 -0
  395. package/src/components/composites/file-tree/file-tree.tsx +405 -0
  396. package/src/components/composites/file-tree/index.ts +25 -0
  397. package/src/components/composites/inline-citation/citation.ts +78 -0
  398. package/src/components/composites/inline-citation/index.ts +9 -0
  399. package/src/components/composites/inline-citation/inline-citation.tsx +285 -0
  400. package/src/components/composites/message-scroller/index.ts +2 -0
  401. package/src/components/composites/message-scroller/message-scroller.tsx +301 -0
  402. package/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
  403. package/src/components/composites/model-selector/index.ts +14 -0
  404. package/src/components/composites/model-selector/model-selector.tsx +420 -0
  405. package/src/components/composites/model-selector/models.ts +103 -0
  406. package/src/components/composites/plan/index.ts +1 -0
  407. package/src/components/composites/plan/plan.tsx +155 -0
  408. package/src/components/composites/queue/index.ts +10 -0
  409. package/src/components/composites/queue/queue.tsx +264 -0
  410. package/src/components/composites/reasoning/index.ts +1 -0
  411. package/src/components/composites/reasoning/reasoning.tsx +176 -0
  412. package/src/components/composites/sources/index.ts +11 -0
  413. package/src/components/composites/sources/source.ts +116 -0
  414. package/src/components/composites/sources/sources.tsx +163 -0
  415. package/src/components/composites/stack-trace/index.ts +19 -0
  416. package/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
  417. package/src/components/composites/stack-trace/stack-trace.tsx +395 -0
  418. package/src/components/composites/subagent/index.ts +1 -0
  419. package/src/components/composites/subagent/subagent.tsx +159 -0
  420. package/src/components/composites/suggestion/index.ts +1 -0
  421. package/src/components/composites/suggestion/suggestion.tsx +140 -0
  422. package/src/components/composites/task/index.ts +14 -0
  423. package/src/components/composites/task/task.tsx +317 -0
  424. package/src/components/composites/terminal/ansi.ts +674 -0
  425. package/src/components/composites/terminal/index.ts +20 -0
  426. package/src/components/composites/terminal/terminal-model.ts +111 -0
  427. package/src/components/composites/terminal/terminal.tsx +574 -0
  428. package/src/components/composites/test-results/index.ts +20 -0
  429. package/src/components/composites/test-results/test-results-model.ts +368 -0
  430. package/src/components/composites/test-results/test-results.tsx +586 -0
  431. package/src/components/composites/tool/format-tool-value.ts +221 -0
  432. package/src/components/composites/tool/index.ts +2 -0
  433. package/src/components/composites/tool/tool.tsx +228 -0
  434. package/src/components/conversation/conversation-surface.tsx +9 -0
  435. package/src/components/conversation/scroll-follow-core.ts +31 -0
  436. package/src/components/conversation/scroll-follow.ts +92 -0
  437. package/src/components/ui/attachment/attachment.tsx +282 -0
  438. package/src/components/ui/attachment/index.ts +10 -0
  439. package/src/components/ui/bubble/bubble.tsx +86 -0
  440. package/src/components/ui/bubble/index.ts +1 -0
  441. package/src/components/ui/code-block/code-block.tsx +256 -26
  442. package/src/components/ui/code-block/index.ts +9 -1
  443. package/src/components/ui/field/number-field.tsx +51 -14
  444. package/src/components/ui/marker/index.ts +1 -0
  445. package/src/components/ui/marker/marker.tsx +90 -0
  446. package/src/components/ui/message/cite-ranges.ts +144 -0
  447. package/src/components/ui/message/index.ts +23 -0
  448. package/src/components/ui/message/message.tsx +434 -0
  449. package/src/components/ui/message/parse-message-text.ts +450 -0
  450. package/src/components/ui/questionnaire/index.ts +10 -0
  451. package/src/components/ui/questionnaire/questionnaire.tsx +446 -0
  452. package/src/components/ui/trace/index.ts +9 -0
  453. package/src/components/ui/trace/trace.tsx +334 -0
  454. package/src/index.ts +26 -0
  455. package/src/styles/base.css +34 -0
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Keeping the reader's place when content appears above them.
3
+ *
4
+ * The browser's own scroll anchoring does this in some engines for some DOM
5
+ * shapes and not in others (and not at all with `content-visibility`), so it is
6
+ * done explicitly. What is remembered is where the turns around the viewport sit
7
+ * in the document (their distance from the top of the content, which scrolling
8
+ * does not change). After the content moves, the turn the reader is on is found
9
+ * again and the scroll offset is moved by however far it moved in the document, so
10
+ * it sits where it did in the viewport.
11
+ *
12
+ * Only the *content's* movement is undone, because the reader's scrolling does not
13
+ * move a turn in the document. A reader who scrolls while a load is open (a wheel
14
+ * fling or touch momentum that was still running when the load began) keeps the
15
+ * scroll: nothing is restored to an offset captured earlier.
16
+ *
17
+ * It is the turn the reader was on that is measured, found from where the turns sat
18
+ * when the marks were taken and not from where the change has left them: a row above
19
+ * the reader that grows far enough to reach into the view has not become the turn they
20
+ * are reading, and the turn they are reading has moved down by the growth. Nothing
21
+ * below that turn counts: a row further down that sizes itself late (an
22
+ * image, highlighted code, a row leaving `content-visibility`) moves rows below the
23
+ * reader, not the reader. The turns above the reader count, because they are what
24
+ * an insert or a late resize above pushes the view down by.
25
+ */
26
+ export type ScrollAnchor = {
27
+ /** `data-anchor-id` of the first turn in view when the marks were taken, if any turn has one. */
28
+ id: string | undefined
29
+ /**
30
+ * The document position (px from the top of the content) of the turns around the
31
+ * viewport when the marks were taken, by id: a few above the first one in view, it, and
32
+ * some below. Empty when no turn carries an id.
33
+ */
34
+ marks: Map<string, number>
35
+ /** The document position of the bottom edge of each marked turn, when the marks were taken. */
36
+ ends: Map<string, number>
37
+ /** Fallback when no turn carries an id: the scroll height at the last restore. */
38
+ scrollHeight: number
39
+ /** The scroll offset at the last restore. */
40
+ scrollTop: number
41
+ /**
42
+ * When set, only these turns are marked: the ones that were there when the load began.
43
+ * A turn that has just landed is still at its estimated height, so a correction taken
44
+ * from it would come from a row about to resize.
45
+ */
46
+ known?: ReadonlySet<string>
47
+ }
48
+
49
+ const ANCHOR_ATTRIBUTE = 'data-anchor-id'
50
+
51
+ /** Turns marked above the first one in view, and below it. */
52
+ const MARKS_ABOVE = 8
53
+ const MARKS_BELOW = 12
54
+
55
+ /** The ids of the turns in the scroller now. */
56
+ export function anchorIds(scroller: HTMLElement): Set<string> {
57
+ const ids = new Set<string>()
58
+ for (const element of scroller.querySelectorAll<HTMLElement>(`[${ANCHOR_ATTRIBUTE}]`))
59
+ ids.add(element.getAttribute(ANCHOR_ATTRIBUTE)!)
60
+ return ids
61
+ }
62
+
63
+ /** Mark the turns around the viewport: where each sits in the document now. */
64
+ export function captureAnchor(scroller: HTMLElement, known?: ReadonlySet<string>): ScrollAnchor {
65
+ const box = scroller.getBoundingClientRect()
66
+ const scrollTop = scroller.scrollTop
67
+ const marks = new Map<string, number>()
68
+ const ends = new Map<string, number>()
69
+ const above: Array<[string, number, number]> = []
70
+ let id: string | undefined
71
+ let below = 0
72
+ for (const element of scroller.querySelectorAll<HTMLElement>(`[${ANCHOR_ATTRIBUTE}]`)) {
73
+ const turn = element.getAttribute(ANCHOR_ATTRIBUTE)!
74
+ if (known && !known.has(turn)) continue
75
+ const rect = element.getBoundingClientRect()
76
+ const position = rect.top - box.top + scrollTop
77
+ const end = rect.bottom - box.top + scrollTop
78
+ if (id === undefined) {
79
+ if (rect.bottom > box.top) {
80
+ id = turn
81
+ for (const [earlier, where, bottom] of above) {
82
+ marks.set(earlier, where)
83
+ ends.set(earlier, bottom)
84
+ }
85
+ marks.set(turn, position)
86
+ ends.set(turn, end)
87
+ } else {
88
+ above.push([turn, position, end])
89
+ if (above.length > MARKS_ABOVE) above.shift()
90
+ }
91
+ } else {
92
+ marks.set(turn, position)
93
+ ends.set(turn, end)
94
+ below += 1
95
+ if (below >= MARKS_BELOW) break
96
+ }
97
+ }
98
+ return { id, marks, ends, scrollHeight: scroller.scrollHeight, scrollTop }
99
+ }
100
+
101
+ /**
102
+ * The marked turn the reader is on and where it sits in the document now. The turn is
103
+ * chosen by where the marked turns were (the first one that reached into the view at the
104
+ * scroll offset now, or the last one if every marked turn was above it), among those still
105
+ * in the scroller; its position is read from where the content has put it.
106
+ */
107
+ function turnInView(
108
+ scroller: HTMLElement,
109
+ anchor: ScrollAnchor
110
+ ): { id: string; position: number } | undefined {
111
+ const box = scroller.getBoundingClientRect()
112
+ const scrollTop = scroller.scrollTop
113
+ const present = new Map<string, number>()
114
+ for (const element of scroller.querySelectorAll<HTMLElement>(`[${ANCHOR_ATTRIBUTE}]`)) {
115
+ const id = element.getAttribute(ANCHOR_ATTRIBUTE)!
116
+ if (anchor.marks.has(id))
117
+ present.set(id, element.getBoundingClientRect().top - box.top + scrollTop)
118
+ }
119
+ let last: { id: string; position: number } | undefined
120
+ for (const id of anchor.marks.keys()) {
121
+ const position = present.get(id)
122
+ if (position === undefined) continue
123
+ last = { id, position }
124
+ if ((anchor.ends.get(id) ?? Infinity) > scrollTop) return last
125
+ }
126
+ return last
127
+ }
128
+
129
+ /**
130
+ * Put the reader back where the content's movement left them. Returns the correction
131
+ * applied, in px.
132
+ *
133
+ * The turn the reader is on is found among the marked turns, and the scroll offset is
134
+ * moved by how far that turn has moved in the document since the marks were taken: an
135
+ * insert or a late resize above it moves it, scrolling and growth below it do not.
136
+ * The marks are then taken again around wherever the reader now is, so a second restore
137
+ * after the same change finds nothing left to correct, and a reader who has moved on
138
+ * (before this call, in the same task as a change, or by a scroll event that has not
139
+ * yet arrived) is measured from the turn they are on and not from one they have left.
140
+ * Nothing here depends on seeing the scroll event first.
141
+ */
142
+ export function restoreAnchor(scroller: HTMLElement, anchor: ScrollAnchor | undefined): number {
143
+ if (!anchor) return 0
144
+ let correction = 0
145
+ if (anchor.marks.size > 0) {
146
+ const turn = turnInView(scroller, anchor)
147
+ if (turn) correction = turn.position - anchor.marks.get(turn.id)!
148
+ } else if (anchor.id === undefined) {
149
+ // No turn carries an id: the growth since the last restore is added to where the
150
+ // reader is, so a second restore after the same insert (the observer and the settle
151
+ // both run one) finds it already applied, and growth that lands later moves the
152
+ // reader only by what is still missing.
153
+ correction = scroller.scrollHeight - anchor.scrollHeight
154
+ }
155
+ if (Math.abs(correction) >= 1) scroller.scrollTop += correction
156
+ const next = captureAnchor(scroller, anchor.known)
157
+ if (next.marks.size > 0 || anchor.marks.size === 0) {
158
+ anchor.id = next.id
159
+ anchor.marks = next.marks
160
+ anchor.ends = next.ends
161
+ } else {
162
+ // None of the turns that were there before the load is in view (the reader is among
163
+ // the rows that landed): keep the old marks, moved by what the content did.
164
+ for (const [id, position] of anchor.marks) anchor.marks.set(id, position + correction)
165
+ for (const [id, end] of anchor.ends) anchor.ends.set(id, end + correction)
166
+ }
167
+ anchor.scrollTop = scroller.scrollTop
168
+ anchor.scrollHeight = scroller.scrollHeight
169
+ return correction
170
+ }
@@ -0,0 +1,14 @@
1
+ export { ModelSelector, type ModelSelectorProps } from './model-selector'
2
+ export {
3
+ findModel,
4
+ groupModels,
5
+ modelSearchValue,
6
+ MODEL_SEARCH_THRESHOLD,
7
+ needsSearch,
8
+ normalizeEfforts,
9
+ resolveEffort,
10
+ type EffortOption,
11
+ type ModelEffort,
12
+ type ModelGroup,
13
+ type ModelOption,
14
+ } from './models'
@@ -0,0 +1,420 @@
1
+ import { Brain, Check, ChevronsUpDown } from 'lucide-solid'
2
+ import {
3
+ createEffect,
4
+ createMemo,
5
+ createSignal,
6
+ createUniqueId,
7
+ For,
8
+ Show,
9
+ splitProps,
10
+ } from 'solid-js'
11
+ import { cn } from '#lib/utils'
12
+ import { Button } from '../../ui/button'
13
+ import {
14
+ Command,
15
+ CommandEmpty,
16
+ CommandGroup,
17
+ CommandInput,
18
+ CommandItem,
19
+ CommandList,
20
+ } from '../../ui/command'
21
+ import {
22
+ DropdownMenu,
23
+ DropdownMenuContent,
24
+ DropdownMenuGroup,
25
+ DropdownMenuLabel,
26
+ DropdownMenuRadioGroup,
27
+ DropdownMenuRadioItem,
28
+ DropdownMenuTrigger,
29
+ } from '../../ui/dropdown-menu'
30
+ import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover'
31
+ import { boundText } from '../sources/source'
32
+ import {
33
+ findModel,
34
+ groupModels,
35
+ modelSearchValue,
36
+ needsSearch,
37
+ normalizeEfforts,
38
+ resolveEffort,
39
+ type ModelOption,
40
+ } from './models'
41
+
42
+ /**
43
+ * ModelSelector.
44
+ *
45
+ * Two controls in one group beside the composer: *which model*, and *how hard it
46
+ * thinks*. They are one component because the second depends on the first — an
47
+ * effort level belongs to a model, and switching model can make the chosen effort
48
+ * meaningless — so a host should not have to keep two menus consistent by hand.
49
+ *
50
+ * ## What it takes and what it will not decide
51
+ *
52
+ * `models` carries each option's provider, optional description and optional
53
+ * `disabledReason`; `value` and `effort` are the current choice; `onChange` and
54
+ * `onEffortChange` report a new one. The component holds no selection of its own
55
+ * (the host may veto, persist or reset it) and never decides what is allowed:
56
+ *
57
+ * - **An unavailable model stays in the list**, disabled, with the host's reason
58
+ * beside it in words. Hiding it would leave the person guessing where it went.
59
+ * - **No `onChange`, no menu.** The model is then plain text — a read-only
60
+ * statement of what is running — not a button that does nothing. The same holds
61
+ * for effort and `onEffortChange`.
62
+ * - **Effort renders only when the selected model advertises `efforts`.** A model
63
+ * that does not has no effort control, and a stored `effort` the model does not
64
+ * offer is shown as unset rather than as a level the model never had.
65
+ * - **A `value` that is not in the list is shown as given**, not swapped for a
66
+ * model the person did not choose.
67
+ * - `disabledReason` disables both and says why under the group.
68
+ *
69
+ * ## Short list or long
70
+ *
71
+ * Up to `searchThreshold` models (7) the model picker is a `DropdownMenu` with
72
+ * radio rows grouped by provider: arrows, typeahead and Escape come from the menu
73
+ * contract. Beyond it the list is a `Popover` holding a `Command` palette with a
74
+ * search box, because scanning thirty rows is slower than typing four letters.
75
+ * Both close on choice and return focus to the trigger. Triggers use
76
+ * `aria-disabled` so a blocked control is still reachable and its reason read.
77
+ */
78
+ export type ModelSelectorProps = {
79
+ models: readonly ModelOption[]
80
+ /** The selected model's id. */
81
+ value?: string
82
+ /** The selected effort's id. */
83
+ effort?: string
84
+ onChange?: (id: string) => void
85
+ onEffortChange?: (effort: string) => void
86
+ /** Show a search box above this many models. Default 7. */
87
+ searchThreshold?: number
88
+ /** Why neither control can be used right now. */
89
+ disabledReason?: string
90
+ /** The group's accessible name. */
91
+ label?: string
92
+ class?: string
93
+ }
94
+
95
+ export function ModelSelector(props: ModelSelectorProps) {
96
+ const [local] = splitProps(props, [
97
+ 'models',
98
+ 'value',
99
+ 'effort',
100
+ 'onChange',
101
+ 'onEffortChange',
102
+ 'searchThreshold',
103
+ 'disabledReason',
104
+ 'label',
105
+ 'class',
106
+ ])
107
+ const blocked = () => local.disabledReason !== undefined
108
+ const selected = () => findModel(local.models, local.value)
109
+ const efforts = createMemo(() => normalizeEfforts(selected()?.efforts))
110
+ const effortChoice = () => resolveEffort(selected(), local.effort)
111
+ const reason = () => (local.disabledReason ? boundText(local.disabledReason, 240) : undefined)
112
+ const reasonId = `${createUniqueId()}-reason`
113
+ const describedBy = () => (reason() ? reasonId : undefined)
114
+
115
+ return (
116
+ <div data-slot="model-selector" class={cn('flex min-w-0 flex-col gap-1', local.class)}>
117
+ <div
118
+ role="group"
119
+ aria-label={local.label ?? 'Model and thinking effort'}
120
+ class="flex min-w-0 items-center gap-1"
121
+ >
122
+ <Show
123
+ when={local.onChange}
124
+ fallback={
125
+ <Show when={local.value}>
126
+ <span class="truncate px-2 text-sm text-muted-foreground">
127
+ <span class="visually-hidden">Model: </span>
128
+ {triggerText({ selected: selected(), value: local.value })}
129
+ </span>
130
+ </Show>
131
+ }
132
+ >
133
+ <Show
134
+ when={needsSearch(local.models.length, local.searchThreshold)}
135
+ fallback={
136
+ <ModelMenu
137
+ models={local.models}
138
+ selected={selected()}
139
+ value={local.value}
140
+ blocked={blocked()}
141
+ describedBy={describedBy()}
142
+ onChange={(id) => local.onChange?.(id)}
143
+ />
144
+ }
145
+ >
146
+ <ModelSearch
147
+ models={local.models}
148
+ selected={selected()}
149
+ value={local.value}
150
+ blocked={blocked()}
151
+ describedBy={describedBy()}
152
+ onChange={(id) => local.onChange?.(id)}
153
+ />
154
+ </Show>
155
+ </Show>
156
+ <Show when={efforts().length > 0}>
157
+ <Show
158
+ when={local.onEffortChange}
159
+ fallback={
160
+ <Show when={effortChoice()}>
161
+ {(choice) => (
162
+ <span class="flex items-center gap-1 truncate px-2 text-sm text-muted-foreground">
163
+ <Brain aria-hidden="true" class="size-3.5 shrink-0" />
164
+ <span class="visually-hidden">Thinking effort: </span>
165
+ {choice().label}
166
+ </span>
167
+ )}
168
+ </Show>
169
+ }
170
+ >
171
+ <EffortMenu
172
+ efforts={efforts()}
173
+ value={effortChoice()?.id}
174
+ blocked={blocked()}
175
+ describedBy={describedBy()}
176
+ onChange={(id) => local.onEffortChange?.(id)}
177
+ />
178
+ </Show>
179
+ </Show>
180
+ </div>
181
+ <Show when={reason()}>
182
+ <p id={reasonId} role="status" class="m-0 text-xs text-muted-foreground">
183
+ {reason()}
184
+ </p>
185
+ </Show>
186
+ </div>
187
+ )
188
+ }
189
+
190
+ function triggerText(props: { selected?: ModelOption; value?: string }): string {
191
+ if (props.selected) return boundText(props.selected.label, 60)
192
+ return props.value ? boundText(props.value, 60) : 'Choose a model'
193
+ }
194
+
195
+ function ModelOptionBody(props: { model: ModelOption }) {
196
+ return (
197
+ <span class="flex min-w-0 flex-col">
198
+ <span class="[overflow-wrap:anywhere]">{boundText(props.model.label, 60)}</span>
199
+ <Show when={props.model.description}>
200
+ <span class="text-xs text-muted-foreground [overflow-wrap:anywhere]">
201
+ {boundText(props.model.description ?? '', 160)}
202
+ </span>
203
+ </Show>
204
+ <Show when={props.model.disabledReason}>
205
+ <span class="text-xs text-muted-foreground [overflow-wrap:anywhere]">
206
+ <span class="visually-hidden">Unavailable: </span>
207
+ {boundText(props.model.disabledReason ?? '', 160)}
208
+ </span>
209
+ </Show>
210
+ </span>
211
+ )
212
+ }
213
+
214
+ type PickerProps = {
215
+ models: readonly ModelOption[]
216
+ selected?: ModelOption
217
+ value?: string
218
+ blocked: boolean
219
+ describedBy?: string
220
+ onChange: (id: string) => void
221
+ }
222
+
223
+ function ModelTrigger(props: { selected?: ModelOption; value?: string; empty: boolean }) {
224
+ return (
225
+ <>
226
+ <span class="max-w-48 truncate">
227
+ {props.empty ? 'No models available' : triggerText(props)}
228
+ </span>
229
+ <ChevronsUpDown aria-hidden="true" />
230
+ </>
231
+ )
232
+ }
233
+
234
+ function ModelMenu(props: PickerProps) {
235
+ const [open, setOpen] = createSignal(false)
236
+ const groups = createMemo(() => groupModels(props.models))
237
+ const inert = () => props.blocked || props.models.length === 0
238
+
239
+ createEffect(() => {
240
+ if (inert()) setOpen(false)
241
+ })
242
+
243
+ return (
244
+ <DropdownMenu
245
+ open={open()}
246
+ onOpenChange={(next) => setOpen(next && !inert())}
247
+ placement="top-start"
248
+ gutter={6}
249
+ >
250
+ <DropdownMenuTrigger
251
+ as={Button}
252
+ variant="ghost"
253
+ size="sm"
254
+ aria-label={`Model: ${props.models.length === 0 ? 'none available' : triggerText(props)}`}
255
+ aria-disabled={inert() || undefined}
256
+ aria-describedby={props.describedBy}
257
+ >
258
+ <ModelTrigger
259
+ selected={props.selected}
260
+ value={props.value}
261
+ empty={props.models.length === 0}
262
+ />
263
+ </DropdownMenuTrigger>
264
+ <DropdownMenuContent hideArrow class="w-72 max-w-full">
265
+ <DropdownMenuRadioGroup
266
+ value={props.value ?? ''}
267
+ onChange={(id: unknown) => {
268
+ // Disabled rows cannot be activated, but the guard is the contract.
269
+ const model = typeof id === 'string' ? findModel(props.models, id) : undefined
270
+ if (!props.blocked && model && model.disabledReason === undefined) {
271
+ props.onChange(model.id)
272
+ }
273
+ }}
274
+ >
275
+ <For each={groups()}>
276
+ {(group) => (
277
+ <DropdownMenuGroup>
278
+ <DropdownMenuLabel>{group.provider}</DropdownMenuLabel>
279
+ <For each={group.models}>
280
+ {(model) => (
281
+ <DropdownMenuRadioItem
282
+ value={model.id}
283
+ disabled={inert() || model.disabledReason !== undefined}
284
+ >
285
+ <ModelOptionBody model={model} />
286
+ </DropdownMenuRadioItem>
287
+ )}
288
+ </For>
289
+ </DropdownMenuGroup>
290
+ )}
291
+ </For>
292
+ </DropdownMenuRadioGroup>
293
+ </DropdownMenuContent>
294
+ </DropdownMenu>
295
+ )
296
+ }
297
+
298
+ function ModelSearch(props: PickerProps) {
299
+ const [open, setOpen] = createSignal(false)
300
+ const groups = createMemo(() => groupModels(props.models))
301
+
302
+ createEffect(() => {
303
+ if (props.blocked) setOpen(false)
304
+ })
305
+
306
+ return (
307
+ <Popover
308
+ open={open()}
309
+ onOpenChange={(next) => setOpen(next && !props.blocked)}
310
+ placement="top-start"
311
+ gutter={6}
312
+ >
313
+ <PopoverTrigger
314
+ as={Button}
315
+ variant="ghost"
316
+ size="sm"
317
+ aria-label={`Model: ${triggerText(props)}`}
318
+ aria-disabled={props.blocked || undefined}
319
+ aria-describedby={props.describedBy}
320
+ >
321
+ <ModelTrigger selected={props.selected} value={props.value} empty={false} />
322
+ </PopoverTrigger>
323
+ <PopoverContent class="w-80 max-w-full">
324
+ <Command label="Choose a model">
325
+ <CommandInput placeholder="Search models" />
326
+ <CommandList>
327
+ <CommandEmpty>No model matches.</CommandEmpty>
328
+ <For each={groups()}>
329
+ {(group) => (
330
+ <CommandGroup heading={group.provider}>
331
+ <For each={group.models}>
332
+ {(model) => (
333
+ <CommandItem
334
+ value={modelSearchValue(model)}
335
+ disabled={props.blocked || model.disabledReason !== undefined}
336
+ onSelect={() => {
337
+ if (props.blocked || model.disabledReason !== undefined) return
338
+ props.onChange(model.id)
339
+ setOpen(false)
340
+ }}
341
+ >
342
+ <ModelOptionBody model={model} />
343
+ <Show when={model.id === props.value}>
344
+ <Check aria-hidden="true" class="ms-auto text-primary" />
345
+ <span class="visually-hidden">Current model</span>
346
+ </Show>
347
+ </CommandItem>
348
+ )}
349
+ </For>
350
+ </CommandGroup>
351
+ )}
352
+ </For>
353
+ </CommandList>
354
+ </Command>
355
+ </PopoverContent>
356
+ </Popover>
357
+ )
358
+ }
359
+
360
+ function EffortMenu(props: {
361
+ efforts: ReturnType<typeof normalizeEfforts>
362
+ value?: string
363
+ blocked: boolean
364
+ describedBy?: string
365
+ onChange: (id: string) => void
366
+ }) {
367
+ const [open, setOpen] = createSignal(false)
368
+ const label = () => props.efforts.find((effort) => effort.id === props.value)?.label
369
+
370
+ createEffect(() => {
371
+ if (props.blocked) setOpen(false)
372
+ })
373
+
374
+ return (
375
+ <DropdownMenu
376
+ open={open()}
377
+ onOpenChange={(next) => setOpen(next && !props.blocked)}
378
+ placement="top-start"
379
+ gutter={6}
380
+ >
381
+ <DropdownMenuTrigger
382
+ as={Button}
383
+ variant="ghost"
384
+ size="sm"
385
+ aria-label={`Thinking effort: ${label() ?? 'not set'}`}
386
+ aria-disabled={props.blocked || undefined}
387
+ aria-describedby={props.describedBy}
388
+ >
389
+ <Brain aria-hidden="true" />
390
+ <span aria-hidden="true">{label() ?? 'Effort'}</span>
391
+ </DropdownMenuTrigger>
392
+ <DropdownMenuContent hideArrow class="w-56 max-w-full">
393
+ <DropdownMenuRadioGroup
394
+ value={props.value ?? ''}
395
+ onChange={(id: unknown) => {
396
+ if (!props.blocked && typeof id === 'string') props.onChange(id)
397
+ }}
398
+ >
399
+ <DropdownMenuGroup>
400
+ <DropdownMenuLabel>Thinking effort</DropdownMenuLabel>
401
+ <For each={props.efforts}>
402
+ {(effort) => (
403
+ <DropdownMenuRadioItem value={effort.id} disabled={props.blocked}>
404
+ <span class="flex min-w-0 flex-col">
405
+ <span>{effort.label}</span>
406
+ <Show when={effort.description}>
407
+ <span class="text-xs text-muted-foreground [overflow-wrap:anywhere]">
408
+ {effort.description}
409
+ </span>
410
+ </Show>
411
+ </span>
412
+ </DropdownMenuRadioItem>
413
+ )}
414
+ </For>
415
+ </DropdownMenuGroup>
416
+ </DropdownMenuRadioGroup>
417
+ </DropdownMenuContent>
418
+ </DropdownMenu>
419
+ )
420
+ }