@slices.sh/ai-chat 0.1.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 (393) hide show
  1. package/LICENSE +21 -0
  2. package/dist/exports.json +794 -0
  3. package/dist/fixture/fixture-approval.d.ts +4 -0
  4. package/dist/fixture/fixture-approval.js +59 -0
  5. package/dist/fixture/fixture-artifacts.d.ts +2 -0
  6. package/dist/fixture/fixture-artifacts.js +48 -0
  7. package/dist/fixture/fixture-question.d.ts +5 -0
  8. package/dist/fixture/fixture-question.js +93 -0
  9. package/dist/fixture/fixture-script.d.ts +35 -0
  10. package/dist/fixture/fixture-script.js +280 -0
  11. package/dist/fixture/fixture-selection.d.ts +5 -0
  12. package/dist/fixture/fixture-selection.js +20 -0
  13. package/dist/fixture/fixture.d.ts +20 -0
  14. package/dist/fixture/fixture.js +75 -0
  15. package/dist/fixture/provider.d.ts +15 -0
  16. package/dist/fixture/provider.js +14 -0
  17. package/dist/headless/always-allow.d.ts +2 -0
  18. package/dist/headless/always-allow.js +24 -0
  19. package/dist/headless/answer.d.ts +6 -0
  20. package/dist/headless/answer.js +29 -0
  21. package/dist/headless/approval-error.d.ts +2 -0
  22. package/dist/headless/approval-error.js +16 -0
  23. package/dist/headless/approval-reason.d.ts +2 -0
  24. package/dist/headless/approval-reason.js +13 -0
  25. package/dist/headless/approval-receipt.d.ts +4 -0
  26. package/dist/headless/approval-receipt.js +13 -0
  27. package/dist/headless/approve.d.ts +4 -0
  28. package/dist/headless/approve.js +15 -0
  29. package/dist/headless/branch-navigation.d.ts +2 -0
  30. package/dist/headless/branch-navigation.js +11 -0
  31. package/dist/headless/branch-next.d.ts +2 -0
  32. package/dist/headless/branch-next.js +21 -0
  33. package/dist/headless/branch-page.d.ts +5 -0
  34. package/dist/headless/branch-page.js +13 -0
  35. package/dist/headless/branch-previous.d.ts +2 -0
  36. package/dist/headless/branch-previous.js +21 -0
  37. package/dist/headless/cancel-edit.d.ts +2 -0
  38. package/dist/headless/cancel-edit.js +10 -0
  39. package/dist/headless/cancel-queue-edit.d.ts +2 -0
  40. package/dist/headless/cancel-queue-edit.js +15 -0
  41. package/dist/headless/cancel-queued.d.ts +2 -0
  42. package/dist/headless/cancel-queued.js +15 -0
  43. package/dist/headless/chat-dictation/confirm.d.ts +2 -0
  44. package/dist/headless/chat-dictation/confirm.js +14 -0
  45. package/dist/headless/chat-dictation/index.d.ts +12 -0
  46. package/dist/headless/chat-dictation/index.js +9 -0
  47. package/dist/headless/chat-dictation/input.d.ts +3 -0
  48. package/dist/headless/chat-dictation/input.js +42 -0
  49. package/dist/headless/chat-dictation/root.d.ts +3 -0
  50. package/dist/headless/chat-dictation/root.js +42 -0
  51. package/dist/headless/chat-dictation/text.d.ts +3 -0
  52. package/dist/headless/chat-dictation/text.js +14 -0
  53. package/dist/headless/chat-dictation/voice.d.ts +3 -0
  54. package/dist/headless/chat-dictation/voice.js +35 -0
  55. package/dist/headless/citation-content.d.ts +3 -0
  56. package/dist/headless/citation-content.js +19 -0
  57. package/dist/headless/citation-description.d.ts +2 -0
  58. package/dist/headless/citation-description.js +12 -0
  59. package/dist/headless/citation-root.d.ts +2 -0
  60. package/dist/headless/citation-root.js +13 -0
  61. package/dist/headless/citation-title.d.ts +2 -0
  62. package/dist/headless/citation-title.js +12 -0
  63. package/dist/headless/citation-trigger.d.ts +2 -0
  64. package/dist/headless/citation-trigger.js +12 -0
  65. package/dist/headless/clear-answer.d.ts +5 -0
  66. package/dist/headless/clear-answer.js +19 -0
  67. package/dist/headless/composer-root.d.ts +14 -0
  68. package/dist/headless/composer-root.js +12 -0
  69. package/dist/headless/composer-standalone.d.ts +3 -0
  70. package/dist/headless/composer-standalone.js +10 -0
  71. package/dist/headless/composer.d.ts +3 -0
  72. package/dist/headless/composer.js +24 -0
  73. package/dist/headless/context-usage.d.ts +3 -0
  74. package/dist/headless/context-usage.js +13 -0
  75. package/dist/headless/contexts.d.ts +77 -0
  76. package/dist/headless/contexts.js +53 -0
  77. package/dist/headless/continue.d.ts +4 -0
  78. package/dist/headless/continue.js +26 -0
  79. package/dist/headless/copy.d.ts +11 -0
  80. package/dist/headless/copy.js +21 -0
  81. package/dist/headless/deny.d.ts +4 -0
  82. package/dist/headless/deny.js +15 -0
  83. package/dist/headless/edit-queued.d.ts +2 -0
  84. package/dist/headless/edit-queued.js +15 -0
  85. package/dist/headless/edit.d.ts +2 -0
  86. package/dist/headless/edit.js +17 -0
  87. package/dist/headless/edited-attachments.d.ts +5 -0
  88. package/dist/headless/edited-attachments.js +11 -0
  89. package/dist/headless/edited-input.d.ts +2 -0
  90. package/dist/headless/edited-input.js +28 -0
  91. package/dist/headless/empty.d.ts +3 -0
  92. package/dist/headless/empty.js +12 -0
  93. package/dist/headless/failed.d.ts +15 -0
  94. package/dist/headless/failed.js +17 -0
  95. package/dist/headless/feedback-error.d.ts +2 -0
  96. package/dist/headless/feedback-error.js +11 -0
  97. package/dist/headless/feedback-root.d.ts +2 -0
  98. package/dist/headless/feedback-root.js +24 -0
  99. package/dist/headless/feedback.d.ts +4 -0
  100. package/dist/headless/feedback.js +18 -0
  101. package/dist/headless/file-audio.d.ts +2 -0
  102. package/dist/headless/file-audio.js +16 -0
  103. package/dist/headless/file-context.d.ts +4 -0
  104. package/dist/headless/file-context.js +7 -0
  105. package/dist/headless/file-img.d.ts +2 -0
  106. package/dist/headless/file-img.js +21 -0
  107. package/dist/headless/file-kind-gate.d.ts +5 -0
  108. package/dist/headless/file-kind-gate.js +11 -0
  109. package/dist/headless/file-link.d.ts +3 -0
  110. package/dist/headless/file-link.js +14 -0
  111. package/dist/headless/file-root.d.ts +5 -0
  112. package/dist/headless/file-root.js +13 -0
  113. package/dist/headless/file-unavailable.d.ts +2 -0
  114. package/dist/headless/file-unavailable.js +12 -0
  115. package/dist/headless/file-video.d.ts +2 -0
  116. package/dist/headless/file-video.js +16 -0
  117. package/dist/headless/follow-ups.d.ts +5 -0
  118. package/dist/headless/follow-ups.js +20 -0
  119. package/dist/headless/forget-approval.d.ts +2 -0
  120. package/dist/headless/forget-approval.js +21 -0
  121. package/dist/headless/gate-content.d.ts +2 -0
  122. package/dist/headless/gate-content.js +6 -0
  123. package/dist/headless/index.d.ts +249 -0
  124. package/dist/headless/index.js +251 -0
  125. package/dist/headless/input.d.ts +11 -0
  126. package/dist/headless/input.js +18 -0
  127. package/dist/headless/jump-to-latest.d.ts +3 -0
  128. package/dist/headless/jump-to-latest.js +14 -0
  129. package/dist/headless/message-edit-root.d.ts +2 -0
  130. package/dist/headless/message-edit-root.js +13 -0
  131. package/dist/headless/message-editing.d.ts +2 -0
  132. package/dist/headless/message-editing.js +10 -0
  133. package/dist/headless/message-editor.d.ts +2 -0
  134. package/dist/headless/message-editor.js +19 -0
  135. package/dist/headless/message-footer.d.ts +3 -0
  136. package/dist/headless/message-footer.js +15 -0
  137. package/dist/headless/message-reading.d.ts +2 -0
  138. package/dist/headless/message-reading.js +10 -0
  139. package/dist/headless/message.d.ts +11 -0
  140. package/dist/headless/message.js +34 -0
  141. package/dist/headless/messages.d.ts +9 -0
  142. package/dist/headless/messages.js +19 -0
  143. package/dist/headless/model-picker.d.ts +2 -0
  144. package/dist/headless/model-picker.js +14 -0
  145. package/dist/headless/model.d.ts +4 -0
  146. package/dist/headless/model.js +13 -0
  147. package/dist/headless/models.d.ts +5 -0
  148. package/dist/headless/models.js +11 -0
  149. package/dist/headless/optional-tools.d.ts +7 -0
  150. package/dist/headless/optional-tools.js +12 -0
  151. package/dist/headless/other-answer.d.ts +5 -0
  152. package/dist/headless/other-answer.js +32 -0
  153. package/dist/headless/part-approval.d.ts +2 -0
  154. package/dist/headless/part-approval.js +33 -0
  155. package/dist/headless/part-file.d.ts +6 -0
  156. package/dist/headless/part-file.js +11 -0
  157. package/dist/headless/part-question.d.ts +2 -0
  158. package/dist/headless/part-question.js +57 -0
  159. package/dist/headless/part-reasoning.d.ts +15 -0
  160. package/dist/headless/part-reasoning.js +26 -0
  161. package/dist/headless/part-source.d.ts +5 -0
  162. package/dist/headless/part-source.js +20 -0
  163. package/dist/headless/part-text.d.ts +16 -0
  164. package/dist/headless/part-text.js +29 -0
  165. package/dist/headless/part-tool.d.ts +16 -0
  166. package/dist/headless/part-tool.js +14 -0
  167. package/dist/headless/parts.d.ts +11 -0
  168. package/dist/headless/parts.js +11 -0
  169. package/dist/headless/question-back.d.ts +2 -0
  170. package/dist/headless/question-back.js +16 -0
  171. package/dist/headless/question-error.d.ts +2 -0
  172. package/dist/headless/question-error.js +14 -0
  173. package/dist/headless/question-invalid.d.ts +8 -0
  174. package/dist/headless/question-invalid.js +18 -0
  175. package/dist/headless/question-item.d.ts +8 -0
  176. package/dist/headless/question-item.js +51 -0
  177. package/dist/headless/question-next.d.ts +3 -0
  178. package/dist/headless/question-next.js +16 -0
  179. package/dist/headless/question-other.d.ts +5 -0
  180. package/dist/headless/question-other.js +22 -0
  181. package/dist/headless/question-progress.d.ts +8 -0
  182. package/dist/headless/question-progress.js +14 -0
  183. package/dist/headless/question-receipt.d.ts +11 -0
  184. package/dist/headless/question-receipt.js +29 -0
  185. package/dist/headless/questions.d.ts +3 -0
  186. package/dist/headless/questions.js +13 -0
  187. package/dist/headless/queue-editing.d.ts +4 -0
  188. package/dist/headless/queue-editing.js +11 -0
  189. package/dist/headless/queue-item.d.ts +2 -0
  190. package/dist/headless/queue-item.js +10 -0
  191. package/dist/headless/queue-items.d.ts +2 -0
  192. package/dist/headless/queue-items.js +11 -0
  193. package/dist/headless/queue-preview.d.ts +6 -0
  194. package/dist/headless/queue-preview.js +11 -0
  195. package/dist/headless/queued-input.d.ts +2 -0
  196. package/dist/headless/queued-input.js +27 -0
  197. package/dist/headless/queued.d.ts +17 -0
  198. package/dist/headless/queued.js +16 -0
  199. package/dist/headless/read-aloud.d.ts +5 -0
  200. package/dist/headless/read-aloud.js +19 -0
  201. package/dist/headless/reasoning-disclosure.d.ts +3 -0
  202. package/dist/headless/reasoning-disclosure.js +17 -0
  203. package/dist/headless/reasoning-timer.d.ts +5 -0
  204. package/dist/headless/reasoning-timer.js +13 -0
  205. package/dist/headless/references.d.ts +6 -0
  206. package/dist/headless/references.js +13 -0
  207. package/dist/headless/regenerate.d.ts +3 -0
  208. package/dist/headless/regenerate.js +22 -0
  209. package/dist/headless/remembered-approval.d.ts +2 -0
  210. package/dist/headless/remembered-approval.js +14 -0
  211. package/dist/headless/root.d.ts +30 -0
  212. package/dist/headless/root.js +99 -0
  213. package/dist/headless/save-edit.d.ts +2 -0
  214. package/dist/headless/save-edit.js +16 -0
  215. package/dist/headless/save-queued.d.ts +2 -0
  216. package/dist/headless/save-queued.js +15 -0
  217. package/dist/headless/send-now.d.ts +2 -0
  218. package/dist/headless/send-now.js +17 -0
  219. package/dist/headless/settings.d.ts +2 -0
  220. package/dist/headless/settings.js +10 -0
  221. package/dist/headless/skip-questions.d.ts +6 -0
  222. package/dist/headless/skip-questions.js +18 -0
  223. package/dist/headless/source-context.d.ts +5 -0
  224. package/dist/headless/source-context.js +9 -0
  225. package/dist/headless/source-link.d.ts +2 -0
  226. package/dist/headless/source-link.js +13 -0
  227. package/dist/headless/source-primitives.d.ts +1 -0
  228. package/dist/headless/source-primitives.js +7 -0
  229. package/dist/headless/source-root.d.ts +5 -0
  230. package/dist/headless/source-root.js +9 -0
  231. package/dist/headless/source-sheet-close.d.ts +2 -0
  232. package/dist/headless/source-sheet-close.js +12 -0
  233. package/dist/headless/source-sheet-content.d.ts +3 -0
  234. package/dist/headless/source-sheet-content.js +16 -0
  235. package/dist/headless/source-sheet-description.d.ts +2 -0
  236. package/dist/headless/source-sheet-description.js +12 -0
  237. package/dist/headless/source-sheet-root.d.ts +2 -0
  238. package/dist/headless/source-sheet-root.js +13 -0
  239. package/dist/headless/source-sheet-title.d.ts +2 -0
  240. package/dist/headless/source-sheet-title.js +12 -0
  241. package/dist/headless/source-sheet-trigger.d.ts +2 -0
  242. package/dist/headless/source-sheet-trigger.js +12 -0
  243. package/dist/headless/source-unavailable.d.ts +2 -0
  244. package/dist/headless/source-unavailable.js +9 -0
  245. package/dist/headless/sources.d.ts +14 -0
  246. package/dist/headless/sources.js +12 -0
  247. package/dist/headless/speaker.d.ts +13 -0
  248. package/dist/headless/speaker.js +10 -0
  249. package/dist/headless/step-boundary.d.ts +4 -0
  250. package/dist/headless/step-boundary.js +16 -0
  251. package/dist/headless/stop.d.ts +10 -0
  252. package/dist/headless/stop.js +18 -0
  253. package/dist/headless/stopped.d.ts +11 -0
  254. package/dist/headless/stopped.js +17 -0
  255. package/dist/headless/submit-answers.d.ts +3 -0
  256. package/dist/headless/submit-answers.js +12 -0
  257. package/dist/headless/submit.d.ts +23 -0
  258. package/dist/headless/submit.js +24 -0
  259. package/dist/headless/suggestion.d.ts +10 -0
  260. package/dist/headless/suggestion.js +14 -0
  261. package/dist/headless/suggestions.d.ts +8 -0
  262. package/dist/headless/suggestions.js +12 -0
  263. package/dist/headless/thread.d.ts +3 -0
  264. package/dist/headless/thread.js +25 -0
  265. package/dist/headless/timing.d.ts +5 -0
  266. package/dist/headless/timing.js +13 -0
  267. package/dist/headless/toggle-tool.d.ts +4 -0
  268. package/dist/headless/toggle-tool.js +15 -0
  269. package/dist/headless/tool-error.d.ts +4 -0
  270. package/dist/headless/tool-error.js +13 -0
  271. package/dist/headless/tool-input.d.ts +4 -0
  272. package/dist/headless/tool-input.js +13 -0
  273. package/dist/headless/tool-output.d.ts +4 -0
  274. package/dist/headless/tool-output.js +13 -0
  275. package/dist/headless/tool-renderer.d.ts +13 -0
  276. package/dist/headless/tool-renderer.js +15 -0
  277. package/dist/headless/transcript.d.ts +23 -0
  278. package/dist/headless/transcript.js +24 -0
  279. package/dist/headless/try-again.d.ts +2 -0
  280. package/dist/headless/try-again.js +24 -0
  281. package/dist/headless/unavailable.d.ts +8 -0
  282. package/dist/headless/unavailable.js +9 -0
  283. package/dist/headless/usage.d.ts +13 -0
  284. package/dist/headless/usage.js +15 -0
  285. package/dist/headless/use-merged-ref.d.ts +2 -0
  286. package/dist/headless/use-merged-ref.js +17 -0
  287. package/dist/headless/use-question.d.ts +3 -0
  288. package/dist/headless/use-question.js +9 -0
  289. package/dist/headless/waiting.d.ts +13 -0
  290. package/dist/headless/waiting.js +12 -0
  291. package/dist/headless/writing.d.ts +13 -0
  292. package/dist/headless/writing.js +12 -0
  293. package/dist/hooks/chat-refusal.d.ts +18 -0
  294. package/dist/hooks/chat-refusal.js +44 -0
  295. package/dist/hooks/turn-mailbox.d.ts +14 -0
  296. package/dist/hooks/turn-mailbox.js +114 -0
  297. package/dist/hooks/use-branches.d.ts +10 -0
  298. package/dist/hooks/use-branches.js +69 -0
  299. package/dist/hooks/use-chat-instance.d.ts +28 -0
  300. package/dist/hooks/use-chat-instance.js +44 -0
  301. package/dist/hooks/use-chat-settings.d.ts +11 -0
  302. package/dist/hooks/use-chat-settings.js +33 -0
  303. package/dist/hooks/use-chat-sink.d.ts +19 -0
  304. package/dist/hooks/use-chat-sink.js +56 -0
  305. package/dist/hooks/use-composer.d.ts +33 -0
  306. package/dist/hooks/use-composer.js +45 -0
  307. package/dist/hooks/use-context-usage.d.ts +8 -0
  308. package/dist/hooks/use-context-usage.js +14 -0
  309. package/dist/hooks/use-copied.d.ts +14 -0
  310. package/dist/hooks/use-copied.js +22 -0
  311. package/dist/hooks/use-draft.d.ts +6 -0
  312. package/dist/hooks/use-draft.js +38 -0
  313. package/dist/hooks/use-feedback.d.ts +8 -0
  314. package/dist/hooks/use-feedback.js +28 -0
  315. package/dist/hooks/use-follow.d.ts +15 -0
  316. package/dist/hooks/use-follow.js +30 -0
  317. package/dist/hooks/use-media-load.d.ts +5 -0
  318. package/dist/hooks/use-media-load.js +12 -0
  319. package/dist/hooks/use-media.d.ts +3 -0
  320. package/dist/hooks/use-media.js +9 -0
  321. package/dist/hooks/use-question-check.d.ts +11 -0
  322. package/dist/hooks/use-question-check.js +29 -0
  323. package/dist/hooks/use-question-draft.d.ts +34 -0
  324. package/dist/hooks/use-question-draft.js +57 -0
  325. package/dist/hooks/use-question-steps.d.ts +18 -0
  326. package/dist/hooks/use-question-steps.js +31 -0
  327. package/dist/hooks/use-question-write.d.ts +8 -0
  328. package/dist/hooks/use-question-write.js +25 -0
  329. package/dist/hooks/use-read-aloud.d.ts +8 -0
  330. package/dist/hooks/use-read-aloud.js +60 -0
  331. package/dist/hooks/use-reasoning.d.ts +8 -0
  332. package/dist/hooks/use-reasoning.js +32 -0
  333. package/dist/hooks/use-remembered-approvals.d.ts +9 -0
  334. package/dist/hooks/use-remembered-approvals.js +40 -0
  335. package/dist/hooks/use-reply.d.ts +3 -0
  336. package/dist/hooks/use-reply.js +9 -0
  337. package/dist/hooks/use-report-missing-configuration.d.ts +9 -0
  338. package/dist/hooks/use-report-missing-configuration.js +14 -0
  339. package/dist/hooks/use-retry-delay.d.ts +5 -0
  340. package/dist/hooks/use-retry-delay.js +17 -0
  341. package/dist/hooks/use-sent-draft.d.ts +8 -0
  342. package/dist/hooks/use-sent-draft.js +25 -0
  343. package/dist/hooks/use-source-disclosure.d.ts +5 -0
  344. package/dist/hooks/use-source-disclosure.js +9 -0
  345. package/dist/hooks/use-sources.d.ts +3 -0
  346. package/dist/hooks/use-sources.js +9 -0
  347. package/dist/hooks/use-tool-approval-memory.d.ts +8 -0
  348. package/dist/hooks/use-tool-approval-memory.js +16 -0
  349. package/dist/hooks/use-tool-approval.d.ts +10 -0
  350. package/dist/hooks/use-tool-approval.js +26 -0
  351. package/dist/hooks/use-turn-queue.d.ts +32 -0
  352. package/dist/hooks/use-turn-queue.js +33 -0
  353. package/dist/index.d.ts +10 -0
  354. package/dist/index.js +5 -0
  355. package/dist/next.d.ts +43 -0
  356. package/dist/next.js +10 -0
  357. package/dist/services/approval-memory.d.ts +9 -0
  358. package/dist/services/approval-memory.js +32 -0
  359. package/dist/services/approval.d.ts +14 -0
  360. package/dist/services/approval.js +37 -0
  361. package/dist/services/branches.d.ts +27 -0
  362. package/dist/services/branches.js +131 -0
  363. package/dist/services/chat-session.d.ts +20 -0
  364. package/dist/services/chat-session.js +61 -0
  365. package/dist/services/choices.d.ts +31 -0
  366. package/dist/services/choices.js +39 -0
  367. package/dist/services/continue.d.ts +8 -0
  368. package/dist/services/continue.js +24 -0
  369. package/dist/services/errors.d.ts +52 -0
  370. package/dist/services/errors.js +54 -0
  371. package/dist/services/media.d.ts +9 -0
  372. package/dist/services/media.js +19 -0
  373. package/dist/services/messages.d.ts +44 -0
  374. package/dist/services/messages.js +0 -0
  375. package/dist/services/optional.d.ts +7 -0
  376. package/dist/services/optional.js +7 -0
  377. package/dist/services/ports.d.ts +31 -0
  378. package/dist/services/ports.js +0 -0
  379. package/dist/services/questions.d.ts +67 -0
  380. package/dist/services/questions.js +119 -0
  381. package/dist/services/request.d.ts +26 -0
  382. package/dist/services/request.js +85 -0
  383. package/dist/services/selection.d.ts +10 -0
  384. package/dist/services/selection.js +49 -0
  385. package/dist/services/sources.d.ts +11 -0
  386. package/dist/services/sources.js +29 -0
  387. package/dist/services/tools.d.ts +11 -0
  388. package/dist/services/tools.js +0 -0
  389. package/dist/services/turn.d.ts +84 -0
  390. package/dist/services/turn.js +0 -0
  391. package/dist/services/types.d.ts +23 -0
  392. package/dist/services/types.js +15 -0
  393. package/package.json +822 -0
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { usePart, useRequired } from "@slices.sh/core/part";
3
+ import { ComposerContext } from "./contexts.js";
4
+ function Suggestion({ text, ...props }) {
5
+ const composer = useRequired(ComposerContext, "Chat.Suggestion must be inside <Chat.Root>.");
6
+ return usePart("button", props, {
7
+ defaults: { type: "button", children: text },
8
+ behavior: { onClick: () => composer.submit(text) },
9
+ locked: { disabled: composer.disabled }
10
+ });
11
+ }
12
+ export {
13
+ Suggestion
14
+ };
@@ -0,0 +1,8 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ /**
3
+ * Starters, and only on an empty transcript.
4
+ *
5
+ * Once there is a conversation they are no longer suggestions, they are a row of buttons
6
+ * competing with what the person was about to type.
7
+ */
8
+ export declare function Suggestions({ children }: GateProps): import("react").ReactNode;
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useChat } from "@ai-sdk/react";
3
+ import { useRequired } from "@slices.sh/core/part";
4
+ import { ChatContext } from "./contexts.js";
5
+ function Suggestions({ children }) {
6
+ const chat = useRequired(ChatContext, "Chat.Suggestions must be inside <Chat.Root>.");
7
+ const { messages } = useChat({ chat });
8
+ return messages.length === 0 ? children : null;
9
+ }
10
+ export {
11
+ Suggestions
12
+ };
@@ -0,0 +1,3 @@
1
+ import { type PartProps } from "@slices.sh/core/part";
2
+ /** Custom renderers retain MessageScroller.Content so anchor children and resizing stay registered. */
3
+ export declare function Thread({ ref, ...props }: PartProps<"div">): import("react").ReactNode;
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from "react";
4
+ import { useMergedRef } from "./use-merged-ref.js";
5
+ import { MessageScroller } from "@shadcn/react/message-scroller";
6
+ import { usePart } from "@slices.sh/core/part";
7
+ function Thread({ ref, ...props }) {
8
+ const element = useRef(null);
9
+ const merged = useMergedRef(element, ref);
10
+ useEffect(() => {
11
+ const content = element.current;
12
+ if (!content) return;
13
+ const registration = content.ownerDocument.createComment("initial-anchor");
14
+ content.append(registration);
15
+ registration.remove();
16
+ }, []);
17
+ return usePart(
18
+ "div",
19
+ { ...props, ref: merged, render: props.render ?? /* @__PURE__ */ jsx(MessageScroller.Content, {}) },
20
+ { locked: { role: "presentation" } }
21
+ );
22
+ }
23
+ export {
24
+ Thread
25
+ };
@@ -0,0 +1,5 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ import type { AiChatMetadata } from "../services/types";
3
+ export declare function Timing({ children }: GateProps<{
4
+ timing: NonNullable<AiChatMetadata["timing"]>;
5
+ }>): import("react").ReactNode;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { useRequired } from "@slices.sh/core/part";
3
+ import { MessageScope } from "./contexts.js";
4
+ import { gateContent } from "./gate-content.js";
5
+ function Timing({ children }) {
6
+ const message = useRequired(MessageScope, "Chat.Timing must be inside <Chat.Messages>.");
7
+ const timing = message.metadata?.timing;
8
+ if (!timing) return null;
9
+ return gateContent(children, { timing });
10
+ }
11
+ export {
12
+ Timing
13
+ };
@@ -0,0 +1,4 @@
1
+ import { type PartProps } from "@slices.sh/core/part";
2
+ export declare function ToggleTool({ tool, ...props }: PartProps<"button"> & {
3
+ tool: string;
4
+ }): import("react").ReactNode;
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { usePart, useRequired } from "@slices.sh/core/part";
3
+ import { SettingsContext } from "./contexts.js";
4
+ function ToggleTool({ tool, ...props }) {
5
+ const settings = useRequired(SettingsContext, "Chat.ToggleTool requires Chat.Root.");
6
+ const part = usePart("button", props, {
7
+ defaults: { type: "button" },
8
+ locked: { disabled: settings.blocked, "aria-pressed": settings.selection.tools?.includes(tool) ?? false },
9
+ behavior: { onClick: () => settings.toggle(tool) }
10
+ });
11
+ return settings.choices?.tools?.some((option) => option.id === tool) ? part : null;
12
+ }
13
+ export {
14
+ ToggleTool
15
+ };
@@ -0,0 +1,4 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ export declare function ToolError({ children }: GateProps<{
3
+ value: string;
4
+ }>): import("react").ReactNode;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { isToolUIPart } from "ai";
3
+ import { useRequired } from "@slices.sh/core/part";
4
+ import { PartScope } from "./contexts.js";
5
+ import { gateContent } from "./gate-content.js";
6
+ function ToolError({ children }) {
7
+ const part = useRequired(PartScope, "Chat.ToolError requires Chat.Parts.");
8
+ if (!isToolUIPart(part) || !(part.state === "output-error")) return null;
9
+ return gateContent(children, { value: part.errorText });
10
+ }
11
+ export {
12
+ ToolError
13
+ };
@@ -0,0 +1,4 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ export declare function ToolInput({ children }: GateProps<{
3
+ value: unknown;
4
+ }>): import("react").ReactNode;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { isToolUIPart } from "ai";
3
+ import { useRequired } from "@slices.sh/core/part";
4
+ import { PartScope } from "./contexts.js";
5
+ import { gateContent } from "./gate-content.js";
6
+ function ToolInput({ children }) {
7
+ const part = useRequired(PartScope, "Chat.ToolInput requires Chat.Parts.");
8
+ if (!isToolUIPart(part) || !(part.input !== void 0)) return null;
9
+ return gateContent(children, { value: part.input });
10
+ }
11
+ export {
12
+ ToolInput
13
+ };
@@ -0,0 +1,4 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ export declare function ToolOutput({ children }: GateProps<{
3
+ value: unknown;
4
+ }>): import("react").ReactNode;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { isToolUIPart } from "ai";
3
+ import { useRequired } from "@slices.sh/core/part";
4
+ import { PartScope } from "./contexts.js";
5
+ import { gateContent } from "./gate-content.js";
6
+ function ToolOutput({ children }) {
7
+ const part = useRequired(PartScope, "Chat.ToolOutput requires Chat.Parts.");
8
+ if (!isToolUIPart(part) || !(part.state === "output-available")) return null;
9
+ return gateContent(children, { value: part.output });
10
+ }
11
+ export {
12
+ ToolOutput
13
+ };
@@ -0,0 +1,13 @@
1
+ import { type DynamicToolUIPart, type ToolUIPart } from "ai";
2
+ import type { ComponentType } from "react";
3
+ import { type RootProps } from "@slices.sh/core/part";
4
+ export type ToolView = (ToolUIPart | DynamicToolUIPart) & {
5
+ toolName: string;
6
+ };
7
+ export type ToolRenderers = Record<string, ComponentType<{
8
+ tool: ToolView;
9
+ }>>;
10
+ /** Render only the tool body; approval controls stay outside the app's renderer. */
11
+ export declare function ToolRenderer({ renderers, children }: RootProps & {
12
+ renderers?: ToolRenderers;
13
+ }): string | number | bigint | boolean | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { getToolName, isToolUIPart } from "ai";
4
+ import { useRequired } from "@slices.sh/core/part";
5
+ import { PartScope } from "./contexts.js";
6
+ function ToolRenderer({ renderers, children }) {
7
+ const part = useRequired(PartScope, "Chat.ToolRenderer requires Chat.Parts.");
8
+ if (!isToolUIPart(part)) return null;
9
+ const name = getToolName(part);
10
+ const Renderer = renderers && Object.hasOwn(renderers, name) ? renderers[name] : void 0;
11
+ return Renderer ? /* @__PURE__ */ jsx(Renderer, { tool: { ...part, toolName: name } }) : children;
12
+ }
13
+ export {
14
+ ToolRenderer
15
+ };
@@ -0,0 +1,23 @@
1
+ import { type PartProps } from "@slices.sh/core/part";
2
+ /**
3
+ * The scroller, and the only one.
4
+ *
5
+ * A second scroller inside it produces a transcript that follows an end nobody can see: the
6
+ * outer one is already at its bottom, and the words arrive somewhere off screen.
7
+ *
8
+ * `role="log"` with `tabIndex` is the pair the APG asks for and the pair this was missing:
9
+ * the role makes arriving messages announce themselves, and the tab stop is the only way a
10
+ * keyboard reaches a scrolling region whose contents — bubbles, avatars — are not focusable.
11
+ *
12
+ * The busy flag belongs on the message being written and not here. On the region it held
13
+ * back everything the region was for: a polite log defers what arrives inside a busy node,
14
+ * so the question the person just sent and the note saying an answer is coming were both
15
+ * announced late or not at all — the two announcements that matter most, suppressed to
16
+ * defer the one that already defers itself. → components/headless/ai-chat/message.tsx
17
+ *
18
+ * The reader's own wheel, touch, keys and scrollbar are what take the transcript away from
19
+ * where the scroller put it; the scroller's own moves never do. → hooks/ai-chat/use-follow.ts
20
+ */
21
+ export declare function Transcript(props: PartProps<"div", {
22
+ following: boolean;
23
+ }>): import("react").ReactNode;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { MessageScroller } from "@shadcn/react/message-scroller";
4
+ import { usePart, useRequired } from "@slices.sh/core/part";
5
+ import { FollowContext } from "./contexts.js";
6
+ function Transcript(props) {
7
+ const follow = useRequired(FollowContext, "Chat.Transcript must be inside <Chat.Root>.");
8
+ const own = (event) => {
9
+ if (event.target === event.currentTarget) follow.release();
10
+ };
11
+ return usePart(
12
+ "div",
13
+ { ...props, render: props.render ?? /* @__PURE__ */ jsx(MessageScroller.Viewport, {}) },
14
+ {
15
+ behavior: { onWheel: follow.release, onTouchMove: follow.release, onKeyDown: own, onPointerDown: own },
16
+ state: { following: follow.following },
17
+ defaults: { role: "log", tabIndex: 0, "aria-live": "polite", "aria-relevant": "additions" },
18
+ attributes: { active: follow.following }
19
+ }
20
+ );
21
+ }
22
+ export {
23
+ Transcript
24
+ };
@@ -0,0 +1,2 @@
1
+ import { type PartProps } from "@slices.sh/core/part";
2
+ export declare function TryAgain(props: PartProps<"button">): import("react").ReactNode;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { useRetryDelay } from "../hooks/use-retry-delay.js";
3
+ import { useChat } from "@ai-sdk/react";
4
+ import { usePart, useRequired } from "@slices.sh/core/part";
5
+ import { ChatContext } from "./contexts.js";
6
+ function TryAgain(props) {
7
+ const chat = useRequired(ChatContext, "Chat.TryAgain must be inside <Chat.Root>.");
8
+ const { messages, regenerate, error, status } = useChat({ chat });
9
+ const { seconds, deadline } = useRetryDelay(error);
10
+ const disabled = status !== "error" || seconds > 0;
11
+ const element = usePart("button", props, {
12
+ defaults: { type: "button" },
13
+ locked: { disabled },
14
+ behavior: {
15
+ onClick: () => {
16
+ if (status === "error" && (deadline === null || Date.now() >= deadline)) void regenerate();
17
+ }
18
+ }
19
+ });
20
+ return messages.some((message) => message.role === "user") ? element : null;
21
+ }
22
+ export {
23
+ TryAgain
24
+ };
@@ -0,0 +1,8 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ /**
3
+ * No chat backend is installed at all, and the screen was handed no chat.
4
+ *
5
+ * Distinct from a refused turn, because nothing the person does will help: the app is
6
+ * missing an implementation, and the only useful sentence names the command that adds one.
7
+ */
8
+ export declare function Unavailable({ children }: GateProps): import("react").ReactNode;
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { useRequired } from "@slices.sh/core/part";
3
+ import { SourceContext } from "./contexts.js";
4
+ function Unavailable({ children }) {
5
+ return useRequired(SourceContext, "Chat.Unavailable must be inside <Chat.Root>.") === "missing" ? children : null;
6
+ }
7
+ export {
8
+ Unavailable
9
+ };
@@ -0,0 +1,13 @@
1
+ import type { LanguageModelUsage } from "ai";
2
+ import { type GateProps } from "@slices.sh/core/part";
3
+ /**
4
+ * What the turn cost, where the provider said: the SDK's usage, as the route put it on the
5
+ * message's metadata when the turn finished.
6
+ *
7
+ * Nothing at all where it did not: this field went years declared and never written, and the
8
+ * website that needed it estimated from the length of the text. An estimate on screen is a
9
+ * number people plan against. → docs/rules/capability-honesty.md
10
+ */
11
+ export declare function Usage({ children }: GateProps<{
12
+ usage: LanguageModelUsage;
13
+ }>): import("react").ReactNode;
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { useRequired } from "@slices.sh/core/part";
3
+ import { MessageScope } from "./contexts.js";
4
+ import { gateContent } from "./gate-content.js";
5
+ function Usage({ children }) {
6
+ const message = useRequired(MessageScope, "Chat.Usage must be inside <Chat.Messages>.");
7
+ const usage = message.metadata?.usage;
8
+ if (!usage || ![usage.totalTokens, usage.inputTokens, usage.outputTokens].some((count) => typeof count === "number")) {
9
+ return null;
10
+ }
11
+ return gateContent(children, { usage });
12
+ }
13
+ export {
14
+ Usage
15
+ };
@@ -0,0 +1,2 @@
1
+ import { type Ref } from "react";
2
+ export declare function useMergedRef<T>(ownRef: Ref<T> | undefined, callerRef: Ref<T> | undefined): (node: T | null) => void;
@@ -0,0 +1,17 @@
1
+ import { useCallback } from "react";
2
+ function useMergedRef(ownRef, callerRef) {
3
+ return useCallback(
4
+ (node) => {
5
+ assign(ownRef, node);
6
+ assign(callerRef, node);
7
+ },
8
+ [ownRef, callerRef]
9
+ );
10
+ }
11
+ function assign(ref, node) {
12
+ if (typeof ref === "function") ref(node);
13
+ else if (ref) ref.current = node;
14
+ }
15
+ export {
16
+ useMergedRef
17
+ };
@@ -0,0 +1,3 @@
1
+ import type { Question } from "../services/types";
2
+ /** The question a part is about, by the name the pattern gave it. */
3
+ export declare function useQuestion(name: string, part: string): Question | undefined;
@@ -0,0 +1,9 @@
1
+ import { useRequired } from "@slices.sh/core/part";
2
+ import { QuestionInputContext } from "./contexts.js";
3
+ function useQuestion(name, part) {
4
+ const input = useRequired(QuestionInputContext, `Chat.${part} requires Chat.PartQuestion.`);
5
+ return input.questions.find((question) => question.name === name);
6
+ }
7
+ export {
8
+ useQuestion
9
+ };
@@ -0,0 +1,13 @@
1
+ import { type GateProps } from "@slices.sh/core/part";
2
+ /**
3
+ * Sent, and nothing back yet: the SDK's `submitted`.
4
+ *
5
+ * Its own gate rather than a flag on a wider one, so the condition lives where the rule
6
+ * wants it and the pattern never writes `waiting ? … : null`. Once the words start arriving
7
+ * they are the answer to "is anything happening", and this renders nothing.
8
+ * → docs/rules/states-gate-themselves.md
9
+ *
10
+ * It belongs inside `Chat.Transcript`, whose `role="log"` announces what arrives in it. A
11
+ * second live region around this note would have a screen reader say it twice.
12
+ */
13
+ export declare function Waiting({ children }: GateProps): import("react").ReactNode;
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useChat } from "@ai-sdk/react";
3
+ import { useRequired } from "@slices.sh/core/part";
4
+ import { ChatContext } from "./contexts.js";
5
+ function Waiting({ children }) {
6
+ const chat = useRequired(ChatContext, "Chat.Waiting must be inside <Chat.Root>.");
7
+ const { status } = useChat({ chat });
8
+ return status === "submitted" ? children : null;
9
+ }
10
+ export {
11
+ Waiting
12
+ };
@@ -0,0 +1,13 @@
1
+ import type { ChatStatus } from "ai";
2
+ import type { AiChatMessage } from "../services/types";
3
+ /** Whether this is the answer the chat is writing right now. */
4
+ export declare function isWriting(message: AiChatMessage, messages: AiChatMessage[], status: ChatStatus): boolean;
5
+ /**
6
+ * Whether an answer ended before it finished.
7
+ *
8
+ * The SDK keeps no flag for it and needs none: a text or a trace is `streaming` until its
9
+ * `-end` chunk arrives, so one still `streaming` on a message nobody is writing is one whose
10
+ * stream was cut — stopped, or broken — and it says so in a transcript saved and read back
11
+ * next week too. An answer with nothing in it at all was cut before it said anything.
12
+ */
13
+ export declare function isCutOff(message: AiChatMessage, writing: boolean): boolean;
@@ -0,0 +1,12 @@
1
+ function isWriting(message, messages, status) {
2
+ return message.role === "assistant" && (status === "submitted" || status === "streaming") && messages.at(-1)?.id === message.id;
3
+ }
4
+ function isCutOff(message, writing) {
5
+ if (message.role !== "assistant" || writing) return false;
6
+ const content = message.parts.filter((part) => part.type !== "step-start");
7
+ return message.metadata?.finishReason === "length" || content.length === 0 || content.some((part) => (part.type === "text" || part.type === "reasoning") && part.state === "streaming");
8
+ }
9
+ export {
10
+ isCutOff,
11
+ isWriting
12
+ };
@@ -0,0 +1,18 @@
1
+ import { type ChatErrorSlug } from "../services/types";
2
+ /**
3
+ * Which refusal the AI SDK's error was, so a screen can say something true about it.
4
+ *
5
+ * The SDK holds a failed turn as an `Error`: an `APICallError` with the status and the body
6
+ * when the route refused before streaming, a plain one with the `error` chunk's text when it
7
+ * failed once the stream was open. A route writes the same JSON in both places
8
+ * (→ services/ai-chat/errors.ts), and something in front of it — a proxy, a platform — may
9
+ * answer with a bare status instead, which still says which refusal it was.
10
+ */
11
+ export declare function refusalOf(error: unknown): ChatErrorSlug;
12
+ /**
13
+ * The JSON a route refused with, wherever the SDK put it, or `null` when the failure was not
14
+ * one a route wrote (a dropped connection, a proxy's page).
15
+ */
16
+ export declare function refusalBody(error: unknown): unknown;
17
+ /** Only the contract's absolute deadline survives both HTTP and streaming refusals. */
18
+ export declare function retryAtOf(error: unknown): number | null;
@@ -0,0 +1,44 @@
1
+ import { APICallError } from "ai";
2
+ import { MISSING_CONFIGURATION } from "@slices.sh/core/configuration";
3
+ import { isChatErrorSlug } from "../services/types.js";
4
+ function refusalOf(error) {
5
+ const said = slugIn(refusalBody(error));
6
+ if (said) return said;
7
+ if (APICallError.isInstance(error) && typeof error.statusCode === "number") {
8
+ return STATUS_SLUGS[error.statusCode] ?? "ai-chat/unavailable";
9
+ }
10
+ return "ai-chat/unavailable";
11
+ }
12
+ function refusalBody(error) {
13
+ if (!(error instanceof Error)) return null;
14
+ try {
15
+ return JSON.parse(error.message);
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ function slugIn(body) {
21
+ const slug = body?.error;
22
+ if (slug === MISSING_CONFIGURATION) return "ai-chat/model-unavailable";
23
+ return isChatErrorSlug(slug) ? slug : null;
24
+ }
25
+ const STATUS_SLUGS = {
26
+ 400: "ai-chat/invalid-request",
27
+ 401: "ai-chat/unauthorized",
28
+ 402: "ai-chat/quota-exceeded",
29
+ 403: "ai-chat/forbidden",
30
+ 404: "ai-chat/unknown-chat",
31
+ 429: "ai-chat/rate-limited",
32
+ 502: "ai-chat/model-unavailable",
33
+ 503: "ai-chat/unavailable"
34
+ };
35
+ function retryAtOf(error) {
36
+ const body = refusalBody(error);
37
+ const value = body?.retryAt;
38
+ return isChatErrorSlug(body?.error) && typeof value === "number" && Number.isFinite(value) && value > 0 && value <= 864e13 ? value : null;
39
+ }
40
+ export {
41
+ refusalBody,
42
+ refusalOf,
43
+ retryAtOf
44
+ };
@@ -0,0 +1,14 @@
1
+ import type { FileUIPart } from "ai";
2
+ import type { AiChat } from "./use-chat-instance";
3
+ import type { QueuedTurn, QueueChange } from "./use-turn-queue";
4
+ export declare function createMailbox(): {
5
+ open(): () => void;
6
+ snapshot: () => readonly QueuedTurn[];
7
+ watch(listener: () => void): () => void;
8
+ drain: (chat: AiChat, settled?: boolean) => void;
9
+ apply: (action: QueueChange | {
10
+ type: "enqueue";
11
+ text: string;
12
+ files?: readonly FileUIPart[];
13
+ }, chat: AiChat) => void;
14
+ };
@@ -0,0 +1,114 @@
1
+ import { approvalDecided, blockedBy, skipQuestions } from "../services/types.js";
2
+ function createMailbox() {
3
+ let items = [];
4
+ let sequence = 0;
5
+ let open = false;
6
+ let holds = 0;
7
+ const watchers = /* @__PURE__ */ new Set();
8
+ const change = (next) => {
9
+ items = next;
10
+ for (const watcher of [...watchers]) watcher();
11
+ };
12
+ const running = (chat) => chat.status === "submitted" || chat.status === "streaming";
13
+ const blocker = (chat) => blockedBy(chat.messages, running(chat));
14
+ function hold(chat, work) {
15
+ holds++;
16
+ void work().finally(() => {
17
+ holds--;
18
+ drain(chat);
19
+ });
20
+ }
21
+ let settling = false;
22
+ function settle(chat) {
23
+ if (settling) return;
24
+ settling = true;
25
+ setTimeout(() => {
26
+ settling = false;
27
+ drain(chat, true);
28
+ }, 0);
29
+ }
30
+ function drain(chat, settled = false) {
31
+ if (!open || holds || running(chat) || blocker(chat) || !items.length || items[0].draft !== null) return;
32
+ if (!settled && approvalDecided(chat.messages)) return settle(chat);
33
+ const item = items[0];
34
+ change(items.slice(1));
35
+ hold(chat, () => chat.sendMessage({ text: item.text, ...item.files?.length ? { files: item.files } : {} }));
36
+ }
37
+ function skip(chat, id) {
38
+ hold(chat, async () => {
39
+ if (!await skipQuestions(chat, id)) return;
40
+ if (!items.length || items[0].draft !== null) await chat.sendMessage();
41
+ });
42
+ }
43
+ function apply(action, chat) {
44
+ if (action.type === "enqueue") {
45
+ change([
46
+ ...items,
47
+ {
48
+ id: `queued-${++sequence}`,
49
+ text: action.text,
50
+ draft: null,
51
+ ...action.files?.length ? { files: action.files.map((file) => ({ ...file })) } : {}
52
+ }
53
+ ]);
54
+ drain(chat);
55
+ return;
56
+ }
57
+ if (action.type === "skip-question") {
58
+ skip(chat, action.toolCallId);
59
+ return;
60
+ }
61
+ const item = items.find((item2) => item2.id === action.id);
62
+ if (!item) return;
63
+ switch (action.type) {
64
+ case "remove":
65
+ change(items.filter((row) => row.id !== item.id));
66
+ break;
67
+ case "begin-edit":
68
+ change(items.map((row) => row.id === item.id ? { ...row, draft: row.text } : row));
69
+ break;
70
+ case "edit":
71
+ if (item.draft !== null)
72
+ change(items.map((row) => row.id === item.id ? { ...row, draft: action.text } : row));
73
+ break;
74
+ case "save-edit":
75
+ if (item.draft === null || !item.draft.trim() && !item.files?.length) return;
76
+ change(
77
+ items.map((row) => row.id === item.id ? { ...row, text: item.draft.trim(), draft: null } : row)
78
+ );
79
+ break;
80
+ case "cancel-edit":
81
+ change(items.map((row) => row.id === item.id ? { ...row, draft: null } : row));
82
+ break;
83
+ case "send-now": {
84
+ const waitingFor = blocker(chat);
85
+ if (item.draft !== null || waitingFor !== null && waitingFor !== "question") return;
86
+ change([item, ...items.filter((row) => row.id !== item.id)]);
87
+ if (waitingFor === "question") hold(chat, () => skipQuestions(chat));
88
+ else if (running(chat)) void chat.stop().finally(() => drain(chat));
89
+ break;
90
+ }
91
+ }
92
+ drain(chat);
93
+ }
94
+ return {
95
+ open() {
96
+ open = true;
97
+ return () => {
98
+ open = false;
99
+ };
100
+ },
101
+ snapshot: () => items,
102
+ watch(listener) {
103
+ watchers.add(listener);
104
+ return () => {
105
+ watchers.delete(listener);
106
+ };
107
+ },
108
+ drain,
109
+ apply
110
+ };
111
+ }
112
+ export {
113
+ createMailbox
114
+ };
@@ -0,0 +1,10 @@
1
+ import { type BranchPage } from "../services/types";
2
+ import type { AiChat } from "./use-chat-instance";
3
+ export type Branches = {
4
+ blocked: boolean;
5
+ page: (messageId: string) => BranchPage | null;
6
+ regenerate: (messageId: string) => void;
7
+ edit: (messageId: string, text: string) => boolean;
8
+ move: (groupId: string, delta: number) => void;
9
+ };
10
+ export declare function useBranches(chat: AiChat, enabled?: boolean): Branches;