@buoy-gg/ask-buoy 7.0.35 → 7.0.38

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 (286) hide show
  1. package/README.md +73 -15
  2. package/lib/commonjs/blocks/AskBlocks.js +1 -338
  3. package/lib/commonjs/blocks/BlockRenderer.js +1 -250
  4. package/lib/commonjs/blocks/ChromePrototypes.js +1 -514
  5. package/lib/commonjs/blocks/DataBlocks.js +1 -688
  6. package/lib/commonjs/blocks/ExtraBlocks.js +1 -1854
  7. package/lib/commonjs/blocks/MediaBlocks.js +1 -140
  8. package/lib/commonjs/blocks/ReceiptBlocks.js +1 -586
  9. package/lib/commonjs/blocks/blockText.js +1 -0
  10. package/lib/commonjs/blocks/blockText.test.js +1 -0
  11. package/lib/commonjs/blocks/context.js +1 -42
  12. package/lib/commonjs/blocks/icons.js +1 -96
  13. package/lib/commonjs/blocks/index.js +1 -95
  14. package/lib/commonjs/blocks/listRow.test.js +1 -55
  15. package/lib/commonjs/blocks/pageState.js +1 -34
  16. package/lib/commonjs/blocks/pageState.test.js +1 -57
  17. package/lib/commonjs/blocks/primitives.js +1 -401
  18. package/lib/commonjs/blocks/primitivesIndex.js +1 -62
  19. package/lib/commonjs/components/ApprovalCard.js +1 -140
  20. package/lib/commonjs/components/AskBuoyHeader.js +1 -164
  21. package/lib/commonjs/components/AskBuoyIcon.js +1 -19
  22. package/lib/commonjs/components/AskBuoyModal.js +1 -353
  23. package/lib/commonjs/components/AskBuoySettings.js +1 -69
  24. package/lib/commonjs/components/ChangesBar.js +1 -211
  25. package/lib/commonjs/components/Composer.js +1 -175
  26. package/lib/commonjs/components/EmptyState.js +1 -154
  27. package/lib/commonjs/components/KeyboardPad.js +1 -0
  28. package/lib/commonjs/components/Markdown.js +1 -252
  29. package/lib/commonjs/components/MessageList.js +1 -683
  30. package/lib/commonjs/components/QueuedMessages.js +1 -0
  31. package/lib/commonjs/components/ThinkingStrip.js +1 -223
  32. package/lib/commonjs/components/TypingDots.js +1 -63
  33. package/lib/commonjs/components/markdownParse.js +1 -0
  34. package/lib/commonjs/components/markdownParse.test.js +1 -0
  35. package/lib/commonjs/components/useCopyAction.js +1 -50
  36. package/lib/commonjs/index.js +1 -252
  37. package/lib/commonjs/preset.js +1 -90
  38. package/lib/commonjs/store/activityGroups.js +1 -0
  39. package/lib/commonjs/store/activityGroups.test.js +1 -0
  40. package/lib/commonjs/store/askBuoySettings.js +1 -67
  41. package/lib/commonjs/store/askBuoyStore.js +1 -365
  42. package/lib/commonjs/store/blockPlacement.js +1 -0
  43. package/lib/commonjs/store/blockPlacement.test.js +1 -0
  44. package/lib/commonjs/store/queue.test.js +1 -0
  45. package/lib/commonjs/store/resetConversation.js +1 -0
  46. package/lib/commonjs/store/restorePending.test.js +1 -0
  47. package/lib/commonjs/store/restoredIds.test.js +1 -47
  48. package/lib/commonjs/store/suggestions.js +1 -0
  49. package/lib/commonjs/store/suggestions.test.js +1 -0
  50. package/lib/commonjs/store/systemLine.test.js +1 -0
  51. package/lib/commonjs/store/ticketPrompt.js +1 -0
  52. package/lib/commonjs/store/traceText.js +1 -81
  53. package/lib/commonjs/store/traceText.test.js +1 -112
  54. package/lib/commonjs/store/transcriptPersistence.js +1 -208
  55. package/lib/commonjs/store/transcriptPersistence.test.js +1 -185
  56. package/lib/commonjs/store/turnRendering.test.js +1 -0
  57. package/lib/commonjs/store/useAskBuoy.js +1 -400
  58. package/lib/commonjs/store/useAskBuoySettings.js +1 -14
  59. package/lib/commonjs/sync/askBuoySyncAdapter.js +1 -119
  60. package/lib/commonjs/sync/askBuoySyncAdapter.test.js +1 -141
  61. package/lib/commonjs/sync/wire.js +1 -58
  62. package/lib/commonjs/types.js +1 -6
  63. package/lib/module/blocks/AskBlocks.js +1 -331
  64. package/lib/module/blocks/BlockRenderer.js +1 -245
  65. package/lib/module/blocks/ChromePrototypes.js +1 -503
  66. package/lib/module/blocks/DataBlocks.js +1 -674
  67. package/lib/module/blocks/ExtraBlocks.js +1 -1827
  68. package/lib/module/blocks/MediaBlocks.js +1 -135
  69. package/lib/module/blocks/ReceiptBlocks.js +1 -574
  70. package/lib/module/blocks/blockText.js +1 -0
  71. package/lib/module/blocks/blockText.test.js +1 -0
  72. package/lib/module/blocks/context.js +1 -35
  73. package/lib/module/blocks/icons.js +1 -91
  74. package/lib/module/blocks/index.js +1 -8
  75. package/lib/module/blocks/listRow.test.js +1 -56
  76. package/lib/module/blocks/pageState.js +1 -30
  77. package/lib/module/blocks/pageState.test.js +1 -56
  78. package/lib/module/blocks/primitives.js +1 -389
  79. package/lib/module/blocks/primitivesIndex.js +1 -5
  80. package/lib/module/components/ApprovalCard.js +1 -135
  81. package/lib/module/components/AskBuoyHeader.js +1 -161
  82. package/lib/module/components/AskBuoyIcon.js +1 -8
  83. package/lib/module/components/AskBuoyModal.js +1 -348
  84. package/lib/module/components/AskBuoySettings.js +1 -64
  85. package/lib/module/components/ChangesBar.js +1 -206
  86. package/lib/module/components/Composer.js +1 -170
  87. package/lib/module/components/EmptyState.js +1 -149
  88. package/lib/module/components/KeyboardPad.js +1 -0
  89. package/lib/module/components/Markdown.js +1 -246
  90. package/lib/module/components/MessageList.js +1 -677
  91. package/lib/module/components/QueuedMessages.js +1 -0
  92. package/lib/module/components/ThinkingStrip.js +1 -218
  93. package/lib/module/components/TypingDots.js +1 -58
  94. package/lib/module/components/markdownParse.js +1 -0
  95. package/lib/module/components/markdownParse.test.js +1 -0
  96. package/lib/module/components/useCopyAction.js +1 -46
  97. package/lib/module/index.js +1 -34
  98. package/lib/module/preset.js +1 -73
  99. package/lib/module/store/activityGroups.js +1 -0
  100. package/lib/module/store/activityGroups.test.js +1 -0
  101. package/lib/module/store/askBuoySettings.js +1 -62
  102. package/lib/module/store/askBuoyStore.js +1 -361
  103. package/lib/module/store/blockPlacement.js +1 -0
  104. package/lib/module/store/blockPlacement.test.js +1 -0
  105. package/lib/module/store/queue.test.js +1 -0
  106. package/lib/module/store/resetConversation.js +1 -0
  107. package/lib/module/store/restorePending.test.js +1 -0
  108. package/lib/module/store/restoredIds.test.js +1 -46
  109. package/lib/module/store/suggestions.js +1 -0
  110. package/lib/module/store/suggestions.test.js +1 -0
  111. package/lib/module/store/systemLine.test.js +1 -0
  112. package/lib/module/store/ticketPrompt.js +1 -0
  113. package/lib/module/store/traceText.js +1 -75
  114. package/lib/module/store/traceText.test.js +1 -111
  115. package/lib/module/store/transcriptPersistence.js +1 -198
  116. package/lib/module/store/transcriptPersistence.test.js +1 -184
  117. package/lib/module/store/turnRendering.test.js +1 -0
  118. package/lib/module/store/useAskBuoy.js +1 -394
  119. package/lib/module/store/useAskBuoySettings.js +1 -9
  120. package/lib/module/sync/askBuoySyncAdapter.js +1 -114
  121. package/lib/module/sync/askBuoySyncAdapter.test.js +1 -140
  122. package/lib/module/sync/wire.js +1 -47
  123. package/lib/module/types.js +1 -4
  124. package/lib/typescript/blocks/DataBlocks.d.ts +11 -0
  125. package/lib/typescript/blocks/ExtraBlocks.d.ts +18 -2
  126. package/lib/typescript/blocks/blockText.d.ts +14 -0
  127. package/lib/typescript/blocks/blockText.test.d.ts +2 -0
  128. package/lib/typescript/blocks/primitives.d.ts +16 -1
  129. package/lib/typescript/components/ApprovalCard.d.ts +9 -1
  130. package/lib/typescript/components/AskBuoyHeader.d.ts +31 -1
  131. package/lib/typescript/components/Composer.d.ts +16 -1
  132. package/lib/typescript/components/EmptyState.d.ts +5 -1
  133. package/lib/typescript/components/KeyboardPad.d.ts +33 -0
  134. package/lib/typescript/components/Markdown.d.ts +0 -10
  135. package/lib/typescript/components/MessageList.d.ts +7 -2
  136. package/lib/typescript/components/QueuedMessages.d.ts +10 -0
  137. package/lib/typescript/components/markdownParse.d.ts +49 -0
  138. package/lib/typescript/components/markdownParse.test.d.ts +2 -0
  139. package/lib/typescript/preset.d.ts +4 -2
  140. package/lib/typescript/store/activityGroups.d.ts +29 -0
  141. package/lib/typescript/store/activityGroups.test.d.ts +2 -0
  142. package/lib/typescript/store/askBuoySettings.d.ts +22 -0
  143. package/lib/typescript/store/askBuoyStore.d.ts +174 -9
  144. package/lib/typescript/store/blockPlacement.d.ts +30 -0
  145. package/lib/typescript/store/blockPlacement.test.d.ts +2 -0
  146. package/lib/typescript/store/queue.test.d.ts +2 -0
  147. package/lib/typescript/store/resetConversation.d.ts +38 -0
  148. package/lib/typescript/store/restorePending.test.d.ts +2 -0
  149. package/lib/typescript/store/suggestions.d.ts +32 -0
  150. package/lib/typescript/store/suggestions.test.d.ts +2 -0
  151. package/lib/typescript/store/systemLine.test.d.ts +2 -0
  152. package/lib/typescript/store/ticketPrompt.d.ts +11 -0
  153. package/lib/typescript/store/transcriptPersistence.d.ts +41 -2
  154. package/lib/typescript/store/turnRendering.test.d.ts +2 -0
  155. package/lib/typescript/store/useAskBuoy.d.ts +26 -3
  156. package/lib/typescript/sync/askBuoySyncAdapter.d.ts +29 -6
  157. package/package.json +10 -10
  158. package/lib/commonjs/blocks/AskBlocks.js.map +0 -1
  159. package/lib/commonjs/blocks/BlockRenderer.js.map +0 -1
  160. package/lib/commonjs/blocks/ChromePrototypes.js.map +0 -1
  161. package/lib/commonjs/blocks/DataBlocks.js.map +0 -1
  162. package/lib/commonjs/blocks/ExtraBlocks.js.map +0 -1
  163. package/lib/commonjs/blocks/MediaBlocks.js.map +0 -1
  164. package/lib/commonjs/blocks/ReceiptBlocks.js.map +0 -1
  165. package/lib/commonjs/blocks/context.js.map +0 -1
  166. package/lib/commonjs/blocks/icons.js.map +0 -1
  167. package/lib/commonjs/blocks/index.js.map +0 -1
  168. package/lib/commonjs/blocks/listRow.test.js.map +0 -1
  169. package/lib/commonjs/blocks/pageState.js.map +0 -1
  170. package/lib/commonjs/blocks/pageState.test.js.map +0 -1
  171. package/lib/commonjs/blocks/primitives.js.map +0 -1
  172. package/lib/commonjs/blocks/primitivesIndex.js.map +0 -1
  173. package/lib/commonjs/components/ApprovalCard.js.map +0 -1
  174. package/lib/commonjs/components/AskBuoyHeader.js.map +0 -1
  175. package/lib/commonjs/components/AskBuoyIcon.js.map +0 -1
  176. package/lib/commonjs/components/AskBuoyModal.js.map +0 -1
  177. package/lib/commonjs/components/AskBuoySettings.js.map +0 -1
  178. package/lib/commonjs/components/ChangesBar.js.map +0 -1
  179. package/lib/commonjs/components/Composer.js.map +0 -1
  180. package/lib/commonjs/components/EmptyState.js.map +0 -1
  181. package/lib/commonjs/components/Markdown.js.map +0 -1
  182. package/lib/commonjs/components/MessageList.js.map +0 -1
  183. package/lib/commonjs/components/ThinkingStrip.js.map +0 -1
  184. package/lib/commonjs/components/TypingDots.js.map +0 -1
  185. package/lib/commonjs/components/useCopyAction.js.map +0 -1
  186. package/lib/commonjs/index.js.map +0 -1
  187. package/lib/commonjs/preset.js.map +0 -1
  188. package/lib/commonjs/store/askBuoySettings.js.map +0 -1
  189. package/lib/commonjs/store/askBuoyStore.js.map +0 -1
  190. package/lib/commonjs/store/restoredIds.test.js.map +0 -1
  191. package/lib/commonjs/store/traceText.js.map +0 -1
  192. package/lib/commonjs/store/traceText.test.js.map +0 -1
  193. package/lib/commonjs/store/transcriptPersistence.js.map +0 -1
  194. package/lib/commonjs/store/transcriptPersistence.test.js.map +0 -1
  195. package/lib/commonjs/store/useAskBuoy.js.map +0 -1
  196. package/lib/commonjs/store/useAskBuoySettings.js.map +0 -1
  197. package/lib/commonjs/sync/askBuoySyncAdapter.js.map +0 -1
  198. package/lib/commonjs/sync/askBuoySyncAdapter.test.js.map +0 -1
  199. package/lib/commonjs/sync/wire.js.map +0 -1
  200. package/lib/commonjs/types.js.map +0 -1
  201. package/lib/module/blocks/AskBlocks.js.map +0 -1
  202. package/lib/module/blocks/BlockRenderer.js.map +0 -1
  203. package/lib/module/blocks/ChromePrototypes.js.map +0 -1
  204. package/lib/module/blocks/DataBlocks.js.map +0 -1
  205. package/lib/module/blocks/ExtraBlocks.js.map +0 -1
  206. package/lib/module/blocks/MediaBlocks.js.map +0 -1
  207. package/lib/module/blocks/ReceiptBlocks.js.map +0 -1
  208. package/lib/module/blocks/context.js.map +0 -1
  209. package/lib/module/blocks/icons.js.map +0 -1
  210. package/lib/module/blocks/index.js.map +0 -1
  211. package/lib/module/blocks/listRow.test.js.map +0 -1
  212. package/lib/module/blocks/pageState.js.map +0 -1
  213. package/lib/module/blocks/pageState.test.js.map +0 -1
  214. package/lib/module/blocks/primitives.js.map +0 -1
  215. package/lib/module/blocks/primitivesIndex.js.map +0 -1
  216. package/lib/module/components/ApprovalCard.js.map +0 -1
  217. package/lib/module/components/AskBuoyHeader.js.map +0 -1
  218. package/lib/module/components/AskBuoyIcon.js.map +0 -1
  219. package/lib/module/components/AskBuoyModal.js.map +0 -1
  220. package/lib/module/components/AskBuoySettings.js.map +0 -1
  221. package/lib/module/components/ChangesBar.js.map +0 -1
  222. package/lib/module/components/Composer.js.map +0 -1
  223. package/lib/module/components/EmptyState.js.map +0 -1
  224. package/lib/module/components/Markdown.js.map +0 -1
  225. package/lib/module/components/MessageList.js.map +0 -1
  226. package/lib/module/components/ThinkingStrip.js.map +0 -1
  227. package/lib/module/components/TypingDots.js.map +0 -1
  228. package/lib/module/components/useCopyAction.js.map +0 -1
  229. package/lib/module/index.js.map +0 -1
  230. package/lib/module/preset.js.map +0 -1
  231. package/lib/module/store/askBuoySettings.js.map +0 -1
  232. package/lib/module/store/askBuoyStore.js.map +0 -1
  233. package/lib/module/store/restoredIds.test.js.map +0 -1
  234. package/lib/module/store/traceText.js.map +0 -1
  235. package/lib/module/store/traceText.test.js.map +0 -1
  236. package/lib/module/store/transcriptPersistence.js.map +0 -1
  237. package/lib/module/store/transcriptPersistence.test.js.map +0 -1
  238. package/lib/module/store/useAskBuoy.js.map +0 -1
  239. package/lib/module/store/useAskBuoySettings.js.map +0 -1
  240. package/lib/module/sync/askBuoySyncAdapter.js.map +0 -1
  241. package/lib/module/sync/askBuoySyncAdapter.test.js.map +0 -1
  242. package/lib/module/sync/wire.js.map +0 -1
  243. package/lib/module/types.js.map +0 -1
  244. package/lib/typescript/blocks/AskBlocks.d.ts.map +0 -1
  245. package/lib/typescript/blocks/BlockRenderer.d.ts.map +0 -1
  246. package/lib/typescript/blocks/ChromePrototypes.d.ts.map +0 -1
  247. package/lib/typescript/blocks/DataBlocks.d.ts.map +0 -1
  248. package/lib/typescript/blocks/ExtraBlocks.d.ts.map +0 -1
  249. package/lib/typescript/blocks/MediaBlocks.d.ts.map +0 -1
  250. package/lib/typescript/blocks/ReceiptBlocks.d.ts.map +0 -1
  251. package/lib/typescript/blocks/context.d.ts.map +0 -1
  252. package/lib/typescript/blocks/icons.d.ts.map +0 -1
  253. package/lib/typescript/blocks/index.d.ts.map +0 -1
  254. package/lib/typescript/blocks/listRow.test.d.ts.map +0 -1
  255. package/lib/typescript/blocks/pageState.d.ts.map +0 -1
  256. package/lib/typescript/blocks/pageState.test.d.ts.map +0 -1
  257. package/lib/typescript/blocks/primitives.d.ts.map +0 -1
  258. package/lib/typescript/blocks/primitivesIndex.d.ts.map +0 -1
  259. package/lib/typescript/components/ApprovalCard.d.ts.map +0 -1
  260. package/lib/typescript/components/AskBuoyHeader.d.ts.map +0 -1
  261. package/lib/typescript/components/AskBuoyIcon.d.ts.map +0 -1
  262. package/lib/typescript/components/AskBuoyModal.d.ts.map +0 -1
  263. package/lib/typescript/components/AskBuoySettings.d.ts.map +0 -1
  264. package/lib/typescript/components/ChangesBar.d.ts.map +0 -1
  265. package/lib/typescript/components/Composer.d.ts.map +0 -1
  266. package/lib/typescript/components/EmptyState.d.ts.map +0 -1
  267. package/lib/typescript/components/Markdown.d.ts.map +0 -1
  268. package/lib/typescript/components/MessageList.d.ts.map +0 -1
  269. package/lib/typescript/components/ThinkingStrip.d.ts.map +0 -1
  270. package/lib/typescript/components/TypingDots.d.ts.map +0 -1
  271. package/lib/typescript/components/useCopyAction.d.ts.map +0 -1
  272. package/lib/typescript/index.d.ts.map +0 -1
  273. package/lib/typescript/preset.d.ts.map +0 -1
  274. package/lib/typescript/store/askBuoySettings.d.ts.map +0 -1
  275. package/lib/typescript/store/askBuoyStore.d.ts.map +0 -1
  276. package/lib/typescript/store/restoredIds.test.d.ts.map +0 -1
  277. package/lib/typescript/store/traceText.d.ts.map +0 -1
  278. package/lib/typescript/store/traceText.test.d.ts.map +0 -1
  279. package/lib/typescript/store/transcriptPersistence.d.ts.map +0 -1
  280. package/lib/typescript/store/transcriptPersistence.test.d.ts.map +0 -1
  281. package/lib/typescript/store/useAskBuoy.d.ts.map +0 -1
  282. package/lib/typescript/store/useAskBuoySettings.d.ts.map +0 -1
  283. package/lib/typescript/sync/askBuoySyncAdapter.d.ts.map +0 -1
  284. package/lib/typescript/sync/askBuoySyncAdapter.test.d.ts.map +0 -1
  285. package/lib/typescript/sync/wire.d.ts.map +0 -1
  286. package/lib/typescript/types.d.ts.map +0 -1
@@ -1,677 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * The transcript.
5
- *
6
- * Owns the ONLY scroller in the sheet. JsModal's default wrapper uses
7
- * `contentContainerStyle: { flexGrow: 1 }`, so a `flex: 1` scroller nested
8
- * inside resolves against the CONTENT rather than the viewport: it grows to
9
- * full content height, never scrolls, and the outer wrapper scrolls instead.
10
- * That is invisible to a human and fatal to Detox ("View is not scrollable at
11
- * the given start point"). The sheet passes `disableScrollWrapper` and this
12
- * list is the one scroller.
13
- *
14
- * Layout, and why:
15
- * - The user's messages are bubbles on the right; the assistant's text is
16
- * plain, full-width prose on the left. A grey bubble around every answer
17
- * cost 28pt of width per line and made the two sides look like the same
18
- * speaker.
19
- * - Tool calls render as an ACTIVITY CARD above the answer they produced —
20
- * one row per call, a status mark, a short human title ("Open /bag") and a
21
- * result word ("Done", "12 items", "Not found"). Nothing in a row is
22
- * truncated to the point of being unreadable: the title wraps, and tapping
23
- * the row expands it to the catalog's full sentence plus the tool it ran on.
24
- * The previous version showed the model-facing sentence cut off at two
25
- * lines with the result's JSON key names beside it, which was unreadable
26
- * AND uninformative.
27
- */
28
- import { useCallback, useEffect, useRef, useState } from "react";
29
- import { ActivityIndicator, FlatList, Pressable, StyleSheet, Text, View } from "react-native";
30
- import { AlertTriangle, Check, ChevronDown, ChevronRight, Copy, night, X } from "@buoy-gg/shared-ui";
31
- import { isAskBlock, toolTitle } from "@buoy-gg/agent-core";
32
- import { BlockRenderer } from "../blocks/BlockRenderer";
33
- import { Markdown } from "./Markdown";
34
- import { ThinkingStrip } from "./ThinkingStrip";
35
- import { TypingDots } from "./TypingDots";
36
- import { useCopyAction } from "./useCopyAction";
37
- import { traceToText } from "../store/traceText";
38
- import { useAskBuoySettings } from "../store/useAskBuoySettings";
39
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
40
- function StatusMark({
41
- status
42
- }) {
43
- switch (status) {
44
- case "running":
45
- return /*#__PURE__*/_jsx(ActivityIndicator, {
46
- size: "small",
47
- color: night.color.textSecondary
48
- });
49
- case "ok":
50
- return /*#__PURE__*/_jsx(View, {
51
- style: [styles.mark, styles.markOk],
52
- children: /*#__PURE__*/_jsx(Check, {
53
- size: 10,
54
- color: night.color.onAccent
55
- })
56
- });
57
- case "failed":
58
- return /*#__PURE__*/_jsx(View, {
59
- style: [styles.mark, styles.markFailed],
60
- children: /*#__PURE__*/_jsx(X, {
61
- size: 10,
62
- color: night.color.text
63
- })
64
- });
65
- case "refused":
66
- return /*#__PURE__*/_jsx(View, {
67
- style: [styles.mark, styles.markRefused],
68
- children: /*#__PURE__*/_jsx(AlertTriangle, {
69
- size: 10,
70
- color: night.color.onAccent
71
- })
72
- });
73
- }
74
- }
75
-
76
- /** The trailing word: what happened, in one glance. */
77
- function statusText(call) {
78
- if (call.status === "running") return {
79
- text: "",
80
- tone: "muted"
81
- };
82
- if (call.status === "refused") return {
83
- text: "Refused",
84
- tone: "warning"
85
- };
86
- if (call.status === "failed") return {
87
- text: "Failed",
88
- tone: "danger"
89
- };
90
- return {
91
- text: call.summary || "Done",
92
- tone: "muted"
93
- };
94
- }
95
- function ActivityRow({
96
- call,
97
- last
98
- }) {
99
- const [open, setOpen] = useState(false);
100
- const status = statusText(call);
101
- const Chevron = open ? ChevronDown : ChevronRight;
102
- const failureDetail = call.status === "failed" && call.summary && call.summary !== "Failed" ? call.summary : null;
103
- return /*#__PURE__*/_jsxs(Pressable, {
104
- testID: `buoy-ask-buoy-tool-${call.toolId}`,
105
- accessibilityRole: "button",
106
- accessibilityLabel: `${call.label}, ${status.text || "running"}`,
107
- accessibilityState: {
108
- expanded: open
109
- },
110
- onPress: () => setOpen(v => !v),
111
- style: [styles.row, !last && styles.rowDivider],
112
- children: [/*#__PURE__*/_jsxs(View, {
113
- style: styles.rowLine,
114
- children: [/*#__PURE__*/_jsx(View, {
115
- style: styles.markSlot,
116
- children: /*#__PURE__*/_jsx(StatusMark, {
117
- status: call.status
118
- })
119
- }), /*#__PURE__*/_jsx(Text, {
120
- style: styles.rowTitle,
121
- children: call.label
122
- }), status.text ? /*#__PURE__*/_jsx(Text, {
123
- style: [styles.rowStatus, status.tone === "danger" && styles.rowStatusDanger, status.tone === "warning" && styles.rowStatusWarning],
124
- numberOfLines: 1,
125
- children: status.text
126
- }) : null, /*#__PURE__*/_jsx(Chevron, {
127
- size: 12,
128
- color: night.color.textTertiary
129
- })]
130
- }), open && /*#__PURE__*/_jsxs(View, {
131
- style: styles.rowDetail,
132
- children: [/*#__PURE__*/_jsx(Text, {
133
- style: styles.rowTool,
134
- children: toolTitle(call.toolId).toUpperCase()
135
- }), call.description ? /*#__PURE__*/_jsx(Text, {
136
- style: styles.rowDescription,
137
- children: call.description
138
- }) : null, failureDetail ? /*#__PURE__*/_jsx(Text, {
139
- style: styles.rowFailure,
140
- children: failureDetail
141
- }) : null]
142
- })]
143
- });
144
- }
145
- const COLLAPSE_AFTER = 4;
146
-
147
- /**
148
- * More than four steps collapse to one line — "Did 15 things · 5 failed" —
149
- * with the failed and refused rows pinned so the bad news is never hidden.
150
- */
151
- function ActivityCard({
152
- calls
153
- }) {
154
- const [expanded, setExpanded] = useState(false);
155
- const running = calls.some(c => c.status === "running");
156
- const collapse = calls.length > COLLAPSE_AFTER && !expanded && !running;
157
- const failed = calls.filter(c => c.status === "failed").length;
158
- const refused = calls.filter(c => c.status === "refused").length;
159
- const shown = collapse ? calls.filter(c => c.status === "failed" || c.status === "refused") : calls;
160
- return /*#__PURE__*/_jsxs(View, {
161
- style: styles.card,
162
- testID: "buoy-ask-buoy-activity",
163
- children: [collapse && /*#__PURE__*/_jsx(Pressable, {
164
- onPress: () => setExpanded(true),
165
- accessibilityRole: "button",
166
- style: [styles.row, shown.length > 0 && styles.rowDivider],
167
- testID: "buoy-ask-buoy-activity-expand",
168
- children: /*#__PURE__*/_jsxs(View, {
169
- style: styles.rowLine,
170
- children: [/*#__PURE__*/_jsxs(Text, {
171
- style: styles.rowTitle,
172
- children: ["Did ", calls.length, " things", failed ? ` · ${failed} failed` : "", refused ? ` · ${refused} refused` : ""]
173
- }), /*#__PURE__*/_jsx(ChevronRight, {
174
- size: 12,
175
- color: night.color.textTertiary
176
- })]
177
- })
178
- }), shown.map((c, i) => /*#__PURE__*/_jsx(ActivityRow, {
179
- call: c,
180
- last: i === shown.length - 1
181
- }, c.id))]
182
- });
183
- }
184
-
185
- /** Receipts and model blocks render between the activity card and the prose; Ask blocks last. */
186
- function Blocks({
187
- blocks
188
- }) {
189
- if (blocks.length === 0) return null;
190
- return /*#__PURE__*/_jsx(View, {
191
- style: styles.blocks,
192
- children: blocks.map(({
193
- block
194
- }) => /*#__PURE__*/_jsx(BlockRenderer, {
195
- block: block
196
- }, block.id))
197
- });
198
- }
199
- function UserMessage({
200
- message
201
- }) {
202
- return /*#__PURE__*/_jsx(View, {
203
- style: styles.userWrap,
204
- children: /*#__PURE__*/_jsx(View, {
205
- style: styles.userBubble,
206
- children: /*#__PURE__*/_jsx(Text, {
207
- style: styles.userText,
208
- selectable: true,
209
- children: message.text
210
- })
211
- })
212
- });
213
- }
214
- function AssistantMessage({
215
- message,
216
- onRetry
217
- }) {
218
- const {
219
- showThinking
220
- } = useAskBuoySettings();
221
- const running = message.toolCalls.some(c => c.status === "running");
222
- const waiting = !!message.streaming && message.text.length === 0 && !running;
223
- const askBlocks = message.blocks.filter(b => isAskBlock(b.block));
224
- const showBlocks = message.blocks.filter(b => !isAskBlock(b.block));
225
- return /*#__PURE__*/_jsxs(View, {
226
- style: styles.assistantWrap,
227
- children: [message.toolCalls.length > 0 && /*#__PURE__*/_jsx(ActivityCard, {
228
- calls: message.toolCalls
229
- }), /*#__PURE__*/_jsx(Blocks, {
230
- blocks: showBlocks
231
- }), message.text.length > 0 && /*#__PURE__*/_jsx(Markdown, {
232
- text: message.text,
233
- style: styles.assistantText
234
- }), /*#__PURE__*/_jsx(Blocks, {
235
- blocks: askBlocks
236
- }), showThinking && !message.streaming && /*#__PURE__*/_jsx(ThinkingStrip, {
237
- message: message
238
- }), waiting && /*#__PURE__*/_jsx(TypingDots, {}), message.error && /*#__PURE__*/_jsx(ErrorNote, {
239
- error: message.error,
240
- onRetry: onRetry
241
- })]
242
- });
243
- }
244
-
245
- /**
246
- * A failed turn. The headline is for the tester ("couldn't reach the
247
- * endpoint"); the raw message stays underneath for whoever gets the bug
248
- * report, because "fetch failed: UnexpectedException: The network connection
249
- * was lost" is what a developer needs and nothing a tester can act on.
250
- */
251
- function ErrorNote({
252
- error,
253
- onRetry
254
- }) {
255
- const network = /fetch failed|network|ECONN|timed? ?out|socket|abort/i.test(error);
256
- const headline = network ? "Couldn't reach your AI endpoint. Check the connection and try again." : "Something went wrong with that turn.";
257
- return /*#__PURE__*/_jsxs(View, {
258
- style: styles.errorBox,
259
- testID: "buoy-ask-buoy-error",
260
- children: [/*#__PURE__*/_jsx(AlertTriangle, {
261
- size: 14,
262
- color: night.color.danger
263
- }), /*#__PURE__*/_jsxs(View, {
264
- style: styles.errorBody,
265
- children: [/*#__PURE__*/_jsx(Text, {
266
- style: styles.errorText,
267
- children: headline
268
- }), /*#__PURE__*/_jsx(Text, {
269
- style: styles.errorDetail,
270
- selectable: true,
271
- children: error
272
- }), onRetry && /*#__PURE__*/_jsx(Pressable, {
273
- testID: "buoy-ask-buoy-retry",
274
- accessibilityRole: "button",
275
- onPress: onRetry,
276
- style: ({
277
- pressed
278
- }) => [styles.retry, pressed && styles.retryPressed],
279
- children: /*#__PURE__*/_jsx(Text, {
280
- style: styles.retryText,
281
- children: "Retry"
282
- })
283
- })]
284
- })]
285
- });
286
- }
287
-
288
- /**
289
- * The whole conversation as plain text — the only thing Copy ever produces,
290
- * and the only way a session leaves the DEVICE (what it saves to disk for a
291
- * reload goes nowhere — see `transcriptPersistence`).
292
- *
293
- * Plain text on purpose. This lands in a Slack message, a ticket comment or a
294
- * notes file, all of which are read by a person; a JSON document is a worse
295
- * version of that everywhere except a parser, and nothing here parses it.
296
- *
297
- * With `Show agent thinking` on it carries the working too — the reasoning and
298
- * each step with its parameters — because reading the run somewhere that is
299
- * not a phone is the entire point of that setting.
300
- */
301
- export function transcriptToText(messages, withTrace = false) {
302
- const lines = [];
303
- for (const m of messages) {
304
- if (m.role === "user") {
305
- lines.push(`You: ${m.text}`);
306
- continue;
307
- }
308
- if (withTrace) {
309
- lines.push(...traceToText(m));
310
- } else {
311
- for (const c of m.toolCalls) {
312
- const status = c.status === "failed" || c.status === "refused" ? ` (${c.status})` : "";
313
- lines.push(` · ${c.label}${c.summary ? ` — ${c.summary}` : ""}${status}`);
314
- }
315
- }
316
- if (m.text) lines.push(`Ask Buoy: ${m.text}`);
317
- if (m.error) lines.push(` ! ${m.error}`);
318
- }
319
- return lines.join("\n");
320
- }
321
-
322
- /** Copy, with the result visible for a moment. Shares the header's behaviour. */
323
- function CopyPill({
324
- testID,
325
- label,
326
- getText
327
- }) {
328
- const {
329
- copied,
330
- copy
331
- } = useCopyAction(getText);
332
- return /*#__PURE__*/_jsxs(Pressable, {
333
- testID: testID,
334
- accessibilityRole: "button",
335
- accessibilityLabel: label,
336
- onPress: copy,
337
- style: ({
338
- pressed
339
- }) => [styles.copyBtn, styles.iconBtn, pressed && styles.copyPressed],
340
- children: [copied ? /*#__PURE__*/_jsx(Check, {
341
- size: 11,
342
- color: night.color.accent
343
- }) : /*#__PURE__*/_jsx(Copy, {
344
- size: 11,
345
- color: night.color.textSecondary
346
- }), /*#__PURE__*/_jsx(Text, {
347
- style: [styles.copyText, copied && styles.copiedText],
348
- children: copied ? "Copied" : label
349
- })]
350
- });
351
- }
352
-
353
- /**
354
- * Under a finished answer: one Copy, and nothing else.
355
- *
356
- * It is on EVERY answer rather than only the newest, because the moment you
357
- * decide to keep a conversation is usually a few replies after the one that
358
- * went wrong, and scrolling to the bottom to find the button is friction at
359
- * exactly the wrong time. Every one of them copies the WHOLE chat — one button
360
- * with one meaning beats four pills the reader has to choose between.
361
- */
362
- function TranscriptActions({
363
- messages
364
- }) {
365
- const {
366
- showThinking
367
- } = useAskBuoySettings();
368
- const getText = useCallback(() => transcriptToText(messages, showThinking), [messages, showThinking]);
369
- return /*#__PURE__*/_jsx(View, {
370
- style: styles.transcriptActions,
371
- children: /*#__PURE__*/_jsx(CopyPill, {
372
- testID: "buoy-ask-buoy-copy",
373
- label: "Copy",
374
- getText: getText
375
- })
376
- });
377
- }
378
- function Row({
379
- message,
380
- messages,
381
- onRetry
382
- }) {
383
- if (message.role === "user") return /*#__PURE__*/_jsx(UserMessage, {
384
- message: message
385
- });
386
- const finished = !message.streaming && !message.error;
387
- return /*#__PURE__*/_jsxs(View, {
388
- children: [/*#__PURE__*/_jsx(AssistantMessage, {
389
- message: message,
390
- onRetry: onRetry
391
- }), finished && /*#__PURE__*/_jsx(TranscriptActions, {
392
- messages: messages
393
- })]
394
- });
395
- }
396
- export function MessageList({
397
- messages,
398
- ListHeaderComponent,
399
- ListEmptyComponent,
400
- ListFooterComponent,
401
- onRetry
402
- }) {
403
- const ref = useRef(null);
404
- // Only auto-scroll when the user is already at the bottom. Yanking them back
405
- // down while they are reading an earlier answer is the classic chat-UI sin.
406
- //
407
- // "At the bottom" is decided from the USER's gestures, not from every scroll
408
- // event. An animated scrollToEnd fires intermediate events while the content
409
- // is still growing under it, and reading those as "the user scrolled up"
410
- // silently unpinned the list mid-answer — the reply then streamed in below
411
- // the fold and the last thing on screen was the question.
412
- const pinned = useRef(true);
413
- const dragging = useRef(false);
414
- const measure = useCallback(e => {
415
- const {
416
- contentOffset,
417
- contentSize,
418
- layoutMeasurement
419
- } = e.nativeEvent;
420
- const distance = contentSize.height - layoutMeasurement.height - contentOffset.y;
421
- pinned.current = distance < 80;
422
- }, []);
423
- const onScrollBeginDrag = useCallback(() => {
424
- dragging.current = true;
425
- }, []);
426
- const onScroll = useCallback(e => {
427
- if (dragging.current) measure(e);
428
- }, [measure]);
429
- const onScrollEndDrag = useCallback(e => {
430
- dragging.current = false;
431
- measure(e);
432
- }, [measure]);
433
- const scrollToEnd = useCallback(() => {
434
- if (!pinned.current) return;
435
- // The size change fires before the new row has finished laying out its
436
- // wrapped text; one frame later the end really is the end.
437
- ref.current?.scrollToEnd({
438
- animated: false
439
- });
440
- requestAnimationFrame(() => ref.current?.scrollToEnd({
441
- animated: false
442
- }));
443
- }, []);
444
-
445
- // A row can grow without the list reporting a size change in the same tick
446
- // (an error box appended to the last message). Follow the transcript too.
447
- const last = messages[messages.length - 1];
448
- const tail = last ? `${last.id}:${last.text.length}:${last.toolCalls.length}:${last.error ?? ""}` : "";
449
- useEffect(() => {
450
- scrollToEnd();
451
- }, [tail, scrollToEnd]);
452
- return /*#__PURE__*/_jsx(FlatList, {
453
- ref: ref,
454
- testID: "buoy-ask-buoy-messages-scroll",
455
- style: styles.list,
456
- contentContainerStyle: styles.listContent,
457
- data: messages,
458
- keyExtractor: m => m.id,
459
- renderItem: ({
460
- item
461
- }) => /*#__PURE__*/_jsx(Row, {
462
- message: item,
463
- messages: messages,
464
- onRetry: item.id === last?.id ? onRetry : undefined
465
- }),
466
- onScroll: onScroll,
467
- onScrollBeginDrag: onScrollBeginDrag,
468
- onScrollEndDrag: onScrollEndDrag,
469
- onMomentumScrollEnd: measure,
470
- scrollEventThrottle: 32,
471
- onContentSizeChange: scrollToEnd
472
- // Mandatory with a focused input below: without it the first tap after
473
- // typing only dismisses the keyboard and the button never fires.
474
- ,
475
- keyboardShouldPersistTaps: "handled",
476
- keyboardDismissMode: "interactive",
477
- ListHeaderComponent: ListHeaderComponent,
478
- ListEmptyComponent: ListEmptyComponent,
479
- ListFooterComponent: ListFooterComponent
480
- });
481
- }
482
- const styles = StyleSheet.create({
483
- list: {
484
- flex: 1,
485
- backgroundColor: "transparent"
486
- },
487
- listContent: {
488
- paddingHorizontal: night.gutter,
489
- paddingTop: 12,
490
- paddingBottom: 16,
491
- gap: 16,
492
- flexGrow: 1
493
- },
494
- // User
495
- userWrap: {
496
- alignItems: "flex-end"
497
- },
498
- userBubble: {
499
- maxWidth: "84%",
500
- paddingHorizontal: 14,
501
- paddingVertical: 9,
502
- borderRadius: 18,
503
- borderBottomRightRadius: 6,
504
- backgroundColor: night.color.accentFill,
505
- borderWidth: StyleSheet.hairlineWidth,
506
- borderColor: night.color.accentBorder
507
- },
508
- userText: {
509
- color: night.color.text,
510
- fontSize: night.font.row,
511
- lineHeight: 21
512
- },
513
- // Assistant
514
- assistantWrap: {
515
- alignItems: "stretch",
516
- gap: 10
517
- },
518
- blocks: {
519
- gap: 10
520
- },
521
- assistantText: {
522
- color: night.color.text,
523
- fontSize: night.font.row,
524
- lineHeight: 22,
525
- paddingHorizontal: 2
526
- },
527
- // Activity card
528
- card: {
529
- borderRadius: night.radius.card,
530
- borderWidth: StyleSheet.hairlineWidth,
531
- borderColor: night.color.border,
532
- backgroundColor: night.color.surface,
533
- overflow: "hidden"
534
- },
535
- row: {
536
- paddingHorizontal: 12,
537
- paddingVertical: 10
538
- },
539
- rowDivider: {
540
- borderBottomWidth: StyleSheet.hairlineWidth,
541
- borderBottomColor: night.color.separator
542
- },
543
- rowLine: {
544
- flexDirection: "row",
545
- alignItems: "center",
546
- gap: 10
547
- },
548
- markSlot: {
549
- width: 18,
550
- height: 18,
551
- alignItems: "center",
552
- justifyContent: "center"
553
- },
554
- mark: {
555
- width: 16,
556
- height: 16,
557
- borderRadius: 8,
558
- alignItems: "center",
559
- justifyContent: "center"
560
- },
561
- markOk: {
562
- backgroundColor: night.color.accent
563
- },
564
- markFailed: {
565
- backgroundColor: night.color.danger
566
- },
567
- markRefused: {
568
- backgroundColor: night.color.warning
569
- },
570
- rowTitle: {
571
- flex: 1,
572
- color: night.color.text,
573
- fontSize: night.font.body,
574
- lineHeight: 19
575
- },
576
- rowStatus: {
577
- color: night.color.textTertiary,
578
- fontSize: night.font.caption,
579
- maxWidth: 120
580
- },
581
- rowStatusDanger: {
582
- color: night.color.danger
583
- },
584
- rowStatusWarning: {
585
- color: night.color.warning
586
- },
587
- rowDetail: {
588
- paddingLeft: 28,
589
- paddingTop: 8,
590
- gap: 4
591
- },
592
- rowTool: {
593
- color: night.color.textTertiary,
594
- fontSize: night.font.micro,
595
- fontWeight: "600",
596
- letterSpacing: 0.8
597
- },
598
- rowDescription: {
599
- color: night.color.textSecondary,
600
- fontSize: night.font.caption,
601
- lineHeight: 18
602
- },
603
- rowFailure: {
604
- color: night.color.danger,
605
- fontSize: night.font.caption,
606
- lineHeight: 18
607
- },
608
- // Error
609
- errorBox: {
610
- flexDirection: "row",
611
- alignItems: "flex-start",
612
- gap: 8,
613
- paddingHorizontal: 12,
614
- paddingVertical: 10,
615
- borderRadius: night.radius.row,
616
- backgroundColor: night.color.dangerSoft
617
- },
618
- errorBody: {
619
- flex: 1,
620
- gap: 4
621
- },
622
- errorText: {
623
- color: night.color.danger,
624
- fontSize: night.font.caption,
625
- fontWeight: "600",
626
- lineHeight: 18
627
- },
628
- errorDetail: {
629
- color: night.color.textSecondary,
630
- fontSize: night.font.micro,
631
- lineHeight: 15
632
- },
633
- retry: {
634
- alignSelf: "flex-start",
635
- marginTop: 6,
636
- paddingHorizontal: 14,
637
- paddingVertical: 7,
638
- borderRadius: night.radius.row,
639
- backgroundColor: night.color.button
640
- },
641
- retryPressed: {
642
- opacity: 0.7
643
- },
644
- retryText: {
645
- color: night.color.accent,
646
- fontSize: night.font.caption,
647
- fontWeight: "600"
648
- },
649
- transcriptActions: {
650
- flexDirection: "row",
651
- marginTop: 8
652
- },
653
- copyBtn: {
654
- paddingHorizontal: 10,
655
- paddingVertical: 5,
656
- borderRadius: night.radius.badge,
657
- backgroundColor: night.color.fill
658
- },
659
- iconBtn: {
660
- flexDirection: "row",
661
- alignItems: "center",
662
- gap: 4,
663
- paddingHorizontal: 8
664
- },
665
- copyPressed: {
666
- opacity: 0.7
667
- },
668
- copyText: {
669
- color: night.color.textSecondary,
670
- fontSize: night.font.micro,
671
- fontWeight: "600"
672
- },
673
- copiedText: {
674
- color: night.color.accent
675
- }
676
- });
677
- //# sourceMappingURL=MessageList.js.map
1
+ "use strict";import{memo,useCallback,useEffect,useRef,useState}from"react";import{ActivityIndicator,FlatList,Pressable,StyleSheet,Text,View}from"react-native";import{AlertTriangle,Check,ChevronDown,ChevronRight,Copy,night,X}from"@buoy-gg/shared-ui";import{toolTitle}from"@buoy-gg/agent-core";import{BlockRenderer}from"../blocks/BlockRenderer";import{blocksToText}from"../blocks/blockText";import{groupCalls,turnFooter}from"../store/activityGroups";import{placeBlocks}from"../store/blockPlacement";import{askBuoyStore}from"../store/askBuoyStore";import{Markdown}from"./Markdown";import{ThinkingStrip}from"./ThinkingStrip";import{TypingDots}from"./TypingDots";import{useCopyAction}from"./useCopyAction";import{traceToText}from"../store/traceText";import{useAskBuoySettings}from"../store/useAskBuoySettings";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function StatusMark({status:e}){switch(e){case"running":return _jsx(ActivityIndicator,{size:"small",color:night.color.textSecondary});case"ok":return _jsx(View,{style:[styles.mark,styles.markOk],children:_jsx(Check,{size:10,color:night.color.onAccent})});case"failed":return _jsx(View,{style:[styles.mark,styles.markFailed],children:_jsx(X,{size:10,color:night.color.text})});case"refused":return _jsx(View,{style:[styles.mark,styles.markRefused],children:_jsx(AlertTriangle,{size:10,color:night.color.onAccent})});case"declined":case"stopped":return _jsx(View,{style:[styles.mark,styles.markNotRun],children:_jsx(View,{style:styles.markNotRunBar})})}}function statusText(e){return"running"===e.status?{text:"",tone:"muted"}:"refused"===e.status?{text:"Refused",tone:"warning"}:"failed"===e.status?{text:"Failed",tone:"danger"}:"declined"===e.status?{text:"You declined",tone:"muted"}:"stopped"===e.status?{text:"Not run — stopped",tone:"muted"}:"verified"===e.verification?.status?{text:"Verified",tone:"ok"}:"unverified"===e.verification?.status?{text:"Done · not yet visible",tone:"muted"}:"failed"===e.verification?.status?{text:"Done · check failed",tone:"warning"}:{text:e.summary||"Done",tone:"muted"}}const isExceptional=e=>"failed"===e.status||"refused"===e.status||"declined"===e.status||"stopped"===e.status;function ActivityRow({call:e,receipts:t,last:o}){const[s,r]=useState(!1),i=statusText(e),n=s?ChevronDown:ChevronRight,l="failed"===e.status&&e.summary&&"Failed"!==e.summary?e.summary:null;return _jsxs(View,{style:[styles.row,!o&&styles.rowDivider],children:[_jsxs(Pressable,{testID:`buoy-ask-buoy-tool-${e.toolId}`,accessibilityRole:"button",accessibilityLabel:`${e.label}, ${i.text||"running"}`,accessibilityState:{expanded:s},onPress:()=>r(e=>!e),children:[_jsxs(View,{style:styles.rowLine,children:[_jsx(View,{style:styles.markSlot,children:_jsx(StatusMark,{status:e.status})}),_jsx(Text,{style:styles.rowTitle,children:e.label}),i.text?_jsx(Text,{style:[styles.rowStatus,"danger"===i.tone&&styles.rowStatusDanger,"warning"===i.tone&&styles.rowStatusWarning,"ok"===i.tone&&styles.rowStatusOk],numberOfLines:1,children:i.text}):null,_jsx(n,{size:12,color:night.color.textTertiary})]}),s&&_jsxs(View,{style:styles.rowDetail,children:[_jsx(Text,{style:styles.rowTool,children:toolTitle(e.toolId).toUpperCase()}),e.description?_jsx(Text,{style:styles.rowDescription,children:e.description}):null,l?_jsx(Text,{style:styles.rowFailure,children:l}):null,e.verification?_jsx(Text,{style:[styles.rowDescription,"failed"===e.verification.status&&styles.rowFailure,"verified"===e.verification.status&&styles.rowVerified],testID:`buoy-ask-buoy-verification-${e.verification.status}`,children:e.verification.detail}):null]})]}),s&&t.length>0&&_jsx(View,{style:styles.rowReceipts,testID:`buoy-ask-buoy-tool-receipt-${e.toolId}`,children:t.map(e=>_jsx(BlockRenderer,{block:e},e.id))})]})}function ReadsGroup({label:e,count:t,calls:o,receipts:s,last:r}){const[i,n]=useState(!1),l=i?ChevronDown:ChevronRight;return _jsxs(View,{style:!r&&!i&&styles.rowDivider,children:[_jsx(Pressable,{testID:"buoy-ask-buoy-reads-group",accessibilityRole:"button",accessibilityLabel:`${e}, ${t} reads`,accessibilityState:{expanded:i},onPress:()=>n(e=>!e),style:[styles.row,i&&styles.rowDivider],children:_jsxs(View,{style:styles.rowLine,children:[_jsx(View,{style:styles.markSlot,children:_jsx(StatusMark,{status:"ok"})}),_jsx(Text,{style:styles.rowTitle,children:e}),_jsxs(Text,{style:styles.rowStatus,numberOfLines:1,children:[t," reads"]}),_jsx(l,{size:12,color:night.color.textTertiary})]})}),i&&_jsx(View,{style:styles.groupBody,children:o.map((e,t)=>_jsx(ActivityRow,{call:e,receipts:s.get(e.id)??[],last:r&&t===o.length-1},e.id))})]})}function ActivityCard({calls:e,receipts:t}){const o=groupCalls(e);return _jsx(View,{style:styles.card,testID:"buoy-ask-buoy-activity",children:o.map((e,s)=>"reads"===e.kind?_jsx(ReadsGroup,{label:e.label,count:e.count,calls:e.calls,receipts:t,last:s===o.length-1},e.id):_jsx(ActivityRow,{call:e.call,receipts:t.get(e.call.id)??[],last:s===o.length-1},e.call.id))})}function Blocks({blocks:e}){return 0===e.length?null:_jsx(View,{style:styles.blocks,children:e.map(({block:e})=>_jsx(BlockRenderer,{block:e},e.id))})}function SystemLine({message:e}){return _jsx(View,{style:styles.systemLine,testID:"buoy-ask-buoy-system-line",children:_jsx(Text,{style:styles.systemText,children:e.text})})}function UserMessage({message:e}){return _jsx(View,{style:styles.userWrap,children:_jsx(View,{style:styles.userBubble,children:_jsx(Text,{style:styles.userText,selectable:!0,children:e.text})})})}function AssistantMessage({message:e,onRetry:t,waitingOnUser:o}){const{showThinking:s}=useAskBuoySettings(),r=!!e.streaming&&!o,{nested:i,afterText:n,ask:l}=placeBlocks(e.blocks,e.toolCalls.map(e=>e.id));return _jsxs(View,{style:styles.assistantWrap,children:[e.toolCalls.length>0&&_jsx(ActivityCard,{calls:e.toolCalls,receipts:i}),e.text.length>0&&_jsx(Markdown,{text:e.text,style:styles.assistantText}),_jsx(Blocks,{blocks:n}),_jsx(Blocks,{blocks:l}),s&&!e.streaming&&_jsx(ThinkingStrip,{message:e}),r&&_jsxs(View,{style:styles.waitingRow,children:[_jsx(TypingDots,{}),e.waiting?_jsx(Text,{style:styles.waitingText,testID:"buoy-ask-buoy-waiting",children:e.waiting}):null]}),e.error&&_jsx(ErrorNote,{error:e.error,onRetry:t}),e.stopped&&!e.error&&_jsx(StoppedNote,{onRetry:t,changed:e.toolCalls.some(e=>"ok"===e.status&&!!e.effect&&"read"!==e.effect)})]})}function StoppedNote({onRetry:e,changed:t}){return _jsxs(View,{style:styles.stoppedBox,testID:"buoy-ask-buoy-stopped",children:[_jsx(Text,{style:styles.stoppedText,children:t?"Stopped. Changes already made are listed above.":"Stopped."}),e&&_jsx(Pressable,{testID:"buoy-ask-buoy-retry",accessibilityRole:"button",accessibilityLabel:"Try again",onPress:e,style:({pressed:e})=>[styles.retry,e&&styles.retryPressed],children:_jsx(Text,{style:styles.retryText,children:"Try again"})})]})}function ErrorNote({error:e,onRetry:t}){const o=/fetch failed|network|ECONN|timed? ?out|socket/i.test(e)?"Couldn't reach your AI endpoint. Check the connection and try again.":"Something went wrong with that turn.";return _jsxs(View,{style:styles.errorBox,testID:"buoy-ask-buoy-error",children:[_jsx(AlertTriangle,{size:14,color:night.color.danger}),_jsxs(View,{style:styles.errorBody,children:[_jsx(Text,{style:styles.errorText,children:o}),_jsx(Text,{style:styles.errorDetail,selectable:!0,children:e}),t&&_jsx(Pressable,{testID:"buoy-ask-buoy-retry",accessibilityRole:"button",accessibilityLabel:"Try again",onPress:t,style:({pressed:e})=>[styles.retry,e&&styles.retryPressed],children:_jsx(Text,{style:styles.retryText,children:"Try again"})})]})]})}export function transcriptToText(e,t=!1){const o=[];for(const s of e)if("user"!==s.role)if(s.system)o.push(` — ${s.text}`);else{if(t)o.push(...traceToText(s));else for(const e of s.toolCalls){const t=isExceptional(e)?` (${e.status})`:"";o.push(` · ${e.label}${e.summary?` — ${e.summary}`:""}${t}`)}s.text&&o.push(`Ask Buoy: ${s.text}`);for(const e of blocksToText(s.blocks.map(e=>e.block)))o.push(e);s.error&&o.push(` ! ${s.error}`),s.stopped&&!s.error&&o.push(" ! Stopped by the user.")}else o.push(`You: ${s.text}`);return o.join("\n")}function CopyPill({testID:e,label:t,getText:o}){const{copied:s,copy:r}=useCopyAction(o);return _jsxs(Pressable,{testID:e,accessibilityRole:"button",accessibilityLabel:t,onPress:r,style:({pressed:e})=>[styles.copyBtn,styles.iconBtn,e&&styles.copyPressed],children:[s?_jsx(Check,{size:11,color:night.color.accent}):_jsx(Copy,{size:11,color:night.color.textSecondary}),_jsx(Text,{style:[styles.copyText,s&&styles.copiedText],children:s?"Copied":t})]})}function TranscriptActions({message:e}){const{showThinking:t}=useAskBuoySettings(),o=useCallback(()=>transcriptToText(askBuoyStore.getState().messages,t),[t]),s=turnFooter(e);return _jsxs(View,{style:styles.transcriptActions,children:[s?_jsx(Text,{style:styles.turnFooter,testID:"buoy-ask-buoy-turn-footer",children:s}):null,_jsx(CopyPill,{testID:"buoy-ask-buoy-copy",label:"Copy conversation",getText:o})]})}const Row=memo(function({message:e,onRetry:t,waitingOnUser:o}){if("user"===e.role)return _jsx(UserMessage,{message:e});if(e.system)return _jsx(SystemLine,{message:e});const s=!e.streaming&&!e.error;return _jsxs(View,{children:[_jsx(AssistantMessage,{message:e,onRetry:t,waitingOnUser:o}),s&&_jsx(TranscriptActions,{message:e})]})});export function MessageList({messages:e,ListHeaderComponent:t,ListEmptyComponent:o,ListFooterComponent:s,onRetry:r,waitingOnUser:i}){const n=useRef(null),l=useRef(!0),a=useRef(!1),c=useCallback(e=>{const{contentOffset:t,contentSize:o,layoutMeasurement:s}=e.nativeEvent,r=o.height-s.height-t.y;l.current=r<80},[]),d=useCallback(()=>{a.current=!0},[]),y=useCallback(e=>{a.current&&c(e)},[c]),u=useCallback(e=>{a.current=!1,c(e)},[c]),g=useCallback(()=>{l.current&&(n.current?.scrollToEnd({animated:!1}),requestAnimationFrame(()=>n.current?.scrollToEnd({animated:!1})))},[]),h=e[e.length-1],x=h?`${h.id}:${h.text.length}:${h.toolCalls.length}:${h.error??""}`:"";return useEffect(()=>{g()},[x,g]),_jsx(FlatList,{ref:n,testID:"buoy-ask-buoy-messages-scroll",style:styles.list,contentContainerStyle:styles.listContent,data:e,keyExtractor:e=>e.id,renderItem:({item:e})=>_jsx(Row,{message:e,onRetry:e.id===h?.id?r:void 0,waitingOnUser:e.id===h?.id&&i}),onScroll:y,onScrollBeginDrag:d,onScrollEndDrag:u,onMomentumScrollEnd:c,scrollEventThrottle:32,onContentSizeChange:g,keyboardShouldPersistTaps:"handled",keyboardDismissMode:"interactive",ListHeaderComponent:t,ListEmptyComponent:o,ListFooterComponent:s})}const styles=StyleSheet.create({list:{flex:1,backgroundColor:"transparent"},listContent:{paddingHorizontal:night.gutter,paddingTop:12,paddingBottom:16,gap:16,flexGrow:1},userWrap:{alignItems:"flex-end"},userBubble:{maxWidth:"84%",paddingHorizontal:14,paddingVertical:9,borderRadius:18,borderBottomRightRadius:6,backgroundColor:night.color.accentFill,borderWidth:StyleSheet.hairlineWidth,borderColor:night.color.accentBorder},userText:{color:night.color.text,fontSize:night.font.row,lineHeight:21},systemLine:{alignSelf:"stretch",paddingHorizontal:12,paddingVertical:7,borderRadius:night.radius.row,backgroundColor:night.color.fill},systemText:{color:night.color.textSecondary,fontSize:night.font.micro,lineHeight:16,textAlign:"center"},assistantWrap:{alignItems:"stretch",gap:10},blocks:{gap:10},waitingRow:{flexDirection:"row",alignItems:"center",gap:8},waitingText:{color:night.color.textSecondary,fontSize:night.font.caption},assistantText:{color:night.color.text,fontSize:night.font.row,lineHeight:22,paddingHorizontal:2},card:{borderRadius:night.radius.card,borderWidth:StyleSheet.hairlineWidth,borderColor:night.color.border,backgroundColor:night.color.surface,overflow:"hidden"},row:{paddingHorizontal:12,paddingVertical:10},rowDivider:{borderBottomWidth:StyleSheet.hairlineWidth,borderBottomColor:night.color.separator},rowLine:{flexDirection:"row",alignItems:"center",gap:10},markSlot:{width:18,height:18,alignItems:"center",justifyContent:"center"},mark:{width:16,height:16,borderRadius:8,alignItems:"center",justifyContent:"center"},markOk:{backgroundColor:night.color.accent},markFailed:{backgroundColor:night.color.danger},markRefused:{backgroundColor:night.color.warning},markNotRun:{borderWidth:1.5,borderColor:night.color.textTertiary},markNotRunBar:{width:7,height:1.5,borderRadius:1,backgroundColor:night.color.textSecondary},rowTitle:{flex:1,color:night.color.text,fontSize:night.font.body,lineHeight:19},rowStatus:{color:night.color.textTertiary,fontSize:night.font.caption,maxWidth:120},rowStatusDanger:{color:night.color.danger},rowStatusWarning:{color:night.color.warning},rowStatusOk:{color:night.color.accent},rowVerified:{color:night.color.accent},rowDetail:{paddingLeft:28,paddingTop:8,gap:4},rowTool:{color:night.color.textTertiary,fontSize:night.font.micro,fontWeight:"600",letterSpacing:.8},rowDescription:{color:night.color.textSecondary,fontSize:night.font.caption,lineHeight:18},rowFailure:{color:night.color.danger,fontSize:night.font.caption,lineHeight:18},rowReceipts:{paddingTop:10,gap:10},groupBody:{paddingLeft:14,backgroundColor:night.color.fill},stoppedBox:{alignItems:"flex-start",gap:2,paddingHorizontal:12,paddingVertical:8},stoppedText:{color:night.color.textTertiary,fontSize:night.font.caption,lineHeight:18},errorBox:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:12,paddingVertical:10,borderRadius:night.radius.row,backgroundColor:night.color.dangerSoft},errorBody:{flex:1,gap:4},errorText:{color:night.color.danger,fontSize:night.font.caption,fontWeight:"600",lineHeight:18},errorDetail:{color:night.color.textSecondary,fontSize:night.font.micro,lineHeight:15},retry:{alignSelf:"flex-start",marginTop:6,paddingHorizontal:14,paddingVertical:7,borderRadius:night.radius.row,backgroundColor:night.color.button},retryPressed:{opacity:.7},retryText:{color:night.color.accent,fontSize:night.font.caption,fontWeight:"600"},transcriptActions:{flexDirection:"row",alignItems:"center",gap:10,marginTop:8},turnFooter:{flex:1,color:night.color.textTertiary,fontSize:night.font.micro,fontVariant:["tabular-nums"]},copyBtn:{paddingHorizontal:10,paddingVertical:5,borderRadius:night.radius.badge,backgroundColor:night.color.fill},iconBtn:{flexDirection:"row",alignItems:"center",gap:4,paddingHorizontal:8},copyPressed:{opacity:.7},copyText:{color:night.color.textSecondary,fontSize:night.font.micro,fontWeight:"600"},copiedText:{color:night.color.accent}});