@flanksource/clicky-ui 0.3.43 → 0.3.45

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 (483) hide show
  1. package/README.md +2 -0
  2. package/dist/ai.cjs +4 -2
  3. package/dist/ai.cjs.map +1 -1
  4. package/dist/ai.js +3 -1
  5. package/dist/components/MdxEditorField.cjs +40 -22
  6. package/dist/components/MdxEditorField.cjs.map +1 -1
  7. package/dist/components/MdxEditorField.d.ts.map +1 -1
  8. package/dist/components/MdxEditorField.js +41 -23
  9. package/dist/components/MdxEditorField.js.map +1 -1
  10. package/dist/components/json-schema-form-item-summary.cjs +6 -1
  11. package/dist/components/json-schema-form-item-summary.cjs.map +1 -1
  12. package/dist/components/json-schema-form-item-summary.d.ts.map +1 -1
  13. package/dist/components/json-schema-form-item-summary.js +6 -1
  14. package/dist/components/json-schema-form-item-summary.js.map +1 -1
  15. package/dist/data/CodeBlock.cjs +3 -2
  16. package/dist/data/CodeBlock.cjs.map +1 -1
  17. package/dist/data/CodeBlock.d.ts +3 -1
  18. package/dist/data/CodeBlock.d.ts.map +1 -1
  19. package/dist/data/CodeBlock.js +3 -2
  20. package/dist/data/CodeBlock.js.map +1 -1
  21. package/dist/data/CodeLine.cjs +22 -0
  22. package/dist/data/CodeLine.cjs.map +1 -0
  23. package/dist/data/CodeLine.d.ts +8 -0
  24. package/dist/data/CodeLine.d.ts.map +1 -0
  25. package/dist/data/CodeLine.js +22 -0
  26. package/dist/data/CodeLine.js.map +1 -0
  27. package/dist/data/GraphDiagram.cjs +18 -6
  28. package/dist/data/GraphDiagram.cjs.map +1 -1
  29. package/dist/data/GraphDiagram.d.ts +9 -1
  30. package/dist/data/GraphDiagram.d.ts.map +1 -1
  31. package/dist/data/GraphDiagram.js +18 -6
  32. package/dist/data/GraphDiagram.js.map +1 -1
  33. package/dist/data/GraphDiagramNodes.cjs +38 -29
  34. package/dist/data/GraphDiagramNodes.cjs.map +1 -1
  35. package/dist/data/GraphDiagramNodes.d.ts +8 -2
  36. package/dist/data/GraphDiagramNodes.d.ts.map +1 -1
  37. package/dist/data/GraphDiagramNodes.js +38 -29
  38. package/dist/data/GraphDiagramNodes.js.map +1 -1
  39. package/dist/data/JsonView.cjs +118 -49
  40. package/dist/data/JsonView.cjs.map +1 -1
  41. package/dist/data/JsonView.d.ts +13 -10
  42. package/dist/data/JsonView.d.ts.map +1 -1
  43. package/dist/data/JsonView.js +118 -49
  44. package/dist/data/JsonView.js.map +1 -1
  45. package/dist/data/MarkdownEditor.cjs +2 -2
  46. package/dist/data/MarkdownEditor.cjs.map +1 -1
  47. package/dist/data/MarkdownEditor.js +2 -2
  48. package/dist/data/MarkdownEditor.js.map +1 -1
  49. package/dist/data/ai/AdvancedChatConfig.cjs +90 -249
  50. package/dist/data/ai/AdvancedChatConfig.cjs.map +1 -1
  51. package/dist/data/ai/AdvancedChatConfig.d.ts +2 -5
  52. package/dist/data/ai/AdvancedChatConfig.d.ts.map +1 -1
  53. package/dist/data/ai/AdvancedChatConfig.js +91 -250
  54. package/dist/data/ai/AdvancedChatConfig.js.map +1 -1
  55. package/dist/data/ai/ChatButton.cjs +2 -0
  56. package/dist/data/ai/ChatButton.cjs.map +1 -1
  57. package/dist/data/ai/ChatButton.d.ts +1 -1
  58. package/dist/data/ai/ChatButton.d.ts.map +1 -1
  59. package/dist/data/ai/ChatButton.js +2 -0
  60. package/dist/data/ai/ChatButton.js.map +1 -1
  61. package/dist/data/ai/ChatFab.cjs +5 -1
  62. package/dist/data/ai/ChatFab.cjs.map +1 -1
  63. package/dist/data/ai/ChatFab.d.ts +5 -1
  64. package/dist/data/ai/ChatFab.d.ts.map +1 -1
  65. package/dist/data/ai/ChatFab.js +5 -1
  66. package/dist/data/ai/ChatFab.js.map +1 -1
  67. package/dist/data/ai/ChatWindow.cjs +2 -8
  68. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  69. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  70. package/dist/data/ai/ChatWindow.js +2 -8
  71. package/dist/data/ai/ChatWindow.js.map +1 -1
  72. package/dist/data/ai/ChatWindow.runtime.cjs +0 -5
  73. package/dist/data/ai/ChatWindow.runtime.cjs.map +1 -1
  74. package/dist/data/ai/ChatWindow.runtime.d.ts +0 -2
  75. package/dist/data/ai/ChatWindow.runtime.d.ts.map +1 -1
  76. package/dist/data/ai/ChatWindow.runtime.js +0 -5
  77. package/dist/data/ai/ChatWindow.runtime.js.map +1 -1
  78. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs +2 -2
  79. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs.map +1 -1
  80. package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts.map +1 -1
  81. package/dist/data/ai/PromptRunEditor/runtimeActions.js +2 -2
  82. package/dist/data/ai/PromptRunEditor/runtimeActions.js.map +1 -1
  83. package/dist/data/ai/SessionInspector.approvals.cjs +3 -6
  84. package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
  85. package/dist/data/ai/SessionInspector.approvals.js +3 -6
  86. package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
  87. package/dist/data/ai/SessionViewer.cjs +13 -4
  88. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  89. package/dist/data/ai/SessionViewer.d.ts +5 -1
  90. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  91. package/dist/data/ai/SessionViewer.header.cjs +1 -1
  92. package/dist/data/ai/SessionViewer.header.cjs.map +1 -1
  93. package/dist/data/ai/SessionViewer.header.js +1 -1
  94. package/dist/data/ai/SessionViewer.header.js.map +1 -1
  95. package/dist/data/ai/SessionViewer.js +13 -4
  96. package/dist/data/ai/SessionViewer.js.map +1 -1
  97. package/dist/data/ai/SessionViewer.model.cjs +2 -0
  98. package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
  99. package/dist/data/ai/SessionViewer.model.d.ts +1 -0
  100. package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
  101. package/dist/data/ai/SessionViewer.model.js +2 -0
  102. package/dist/data/ai/SessionViewer.model.js.map +1 -1
  103. package/dist/data/ai/SessionViewer.rows.cjs +41 -27
  104. package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
  105. package/dist/data/ai/SessionViewer.rows.d.ts +4 -2
  106. package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
  107. package/dist/data/ai/SessionViewer.rows.js +41 -27
  108. package/dist/data/ai/SessionViewer.rows.js.map +1 -1
  109. package/dist/data/ai/SessionViewer.tokens.cjs +35 -0
  110. package/dist/data/ai/SessionViewer.tokens.cjs.map +1 -0
  111. package/dist/data/ai/SessionViewer.tokens.d.ts +5 -0
  112. package/dist/data/ai/SessionViewer.tokens.d.ts.map +1 -0
  113. package/dist/data/ai/SessionViewer.tokens.js +35 -0
  114. package/dist/data/ai/SessionViewer.tokens.js.map +1 -0
  115. package/dist/data/ai/SessionViewer.tool-cost.cjs +128 -0
  116. package/dist/data/ai/SessionViewer.tool-cost.cjs.map +1 -0
  117. package/dist/data/ai/SessionViewer.tool-cost.d.ts +6 -0
  118. package/dist/data/ai/SessionViewer.tool-cost.d.ts.map +1 -0
  119. package/dist/data/ai/SessionViewer.tool-cost.js +128 -0
  120. package/dist/data/ai/SessionViewer.tool-cost.js.map +1 -0
  121. package/dist/data/ai/SessionViewer.tool-details.cjs +3 -1
  122. package/dist/data/ai/SessionViewer.tool-details.cjs.map +1 -1
  123. package/dist/data/ai/SessionViewer.tool-details.d.ts.map +1 -1
  124. package/dist/data/ai/SessionViewer.tool-details.js +3 -1
  125. package/dist/data/ai/SessionViewer.tool-details.js.map +1 -1
  126. package/dist/data/ai/SessionViewer.tool-row.cjs +55 -35
  127. package/dist/data/ai/SessionViewer.tool-row.cjs.map +1 -1
  128. package/dist/data/ai/SessionViewer.tool-row.d.ts +2 -1
  129. package/dist/data/ai/SessionViewer.tool-row.d.ts.map +1 -1
  130. package/dist/data/ai/SessionViewer.tool-row.js +55 -35
  131. package/dist/data/ai/SessionViewer.tool-row.js.map +1 -1
  132. package/dist/data/ai/SessionViewer.unified.d.ts +4 -0
  133. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  134. package/dist/data/ai/SessionViewerMenu.cjs +18 -1
  135. package/dist/data/ai/SessionViewerMenu.cjs.map +1 -1
  136. package/dist/data/ai/SessionViewerMenu.d.ts +6 -1
  137. package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -1
  138. package/dist/data/ai/SessionViewerMenu.js +18 -1
  139. package/dist/data/ai/SessionViewerMenu.js.map +1 -1
  140. package/dist/data/ai/ToolPreferences.cjs +149 -143
  141. package/dist/data/ai/ToolPreferences.cjs.map +1 -1
  142. package/dist/data/ai/ToolPreferences.d.ts +20 -6
  143. package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
  144. package/dist/data/ai/ToolPreferences.js +151 -146
  145. package/dist/data/ai/ToolPreferences.js.map +1 -1
  146. package/dist/data/ai/ToolPreferences.model.cjs +14 -10
  147. package/dist/data/ai/ToolPreferences.model.cjs.map +1 -1
  148. package/dist/data/ai/ToolPreferences.model.d.ts +1 -0
  149. package/dist/data/ai/ToolPreferences.model.d.ts.map +1 -1
  150. package/dist/data/ai/ToolPreferences.model.js +15 -11
  151. package/dist/data/ai/ToolPreferences.model.js.map +1 -1
  152. package/dist/data/ai/ToolPreferencesList.cjs +1 -0
  153. package/dist/data/ai/ToolPreferencesList.cjs.map +1 -1
  154. package/dist/data/ai/ToolPreferencesList.d.ts +4 -1
  155. package/dist/data/ai/ToolPreferencesList.d.ts.map +1 -1
  156. package/dist/data/ai/ToolPreferencesList.js +2 -1
  157. package/dist/data/ai/ToolPreferencesList.js.map +1 -1
  158. package/dist/data/ai/ToolSchemaBrowser.cjs +52 -53
  159. package/dist/data/ai/ToolSchemaBrowser.cjs.map +1 -1
  160. package/dist/data/ai/ToolSchemaBrowser.d.ts +6 -3
  161. package/dist/data/ai/ToolSchemaBrowser.d.ts.map +1 -1
  162. package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs +9 -13
  163. package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs.map +1 -1
  164. package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts +5 -2
  165. package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts.map +1 -1
  166. package/dist/data/ai/ToolSchemaBrowser.directory-header.js +9 -13
  167. package/dist/data/ai/ToolSchemaBrowser.directory-header.js.map +1 -1
  168. package/dist/data/ai/ToolSchemaBrowser.js +53 -54
  169. package/dist/data/ai/ToolSchemaBrowser.js.map +1 -1
  170. package/dist/data/ai/ToolSchemaBrowser.model.cjs +19 -27
  171. package/dist/data/ai/ToolSchemaBrowser.model.cjs.map +1 -1
  172. package/dist/data/ai/ToolSchemaBrowser.model.d.ts +9 -6
  173. package/dist/data/ai/ToolSchemaBrowser.model.d.ts.map +1 -1
  174. package/dist/data/ai/ToolSchemaBrowser.model.js +20 -28
  175. package/dist/data/ai/ToolSchemaBrowser.model.js.map +1 -1
  176. package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs +12 -213
  177. package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs.map +1 -1
  178. package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts +1 -3
  179. package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts.map +1 -1
  180. package/dist/data/ai/ToolSchemaBrowser.sidebar.js +13 -214
  181. package/dist/data/ai/ToolSchemaBrowser.sidebar.js.map +1 -1
  182. package/dist/data/ai/ToolSchemaBrowser.strategies.cjs +54 -0
  183. package/dist/data/ai/ToolSchemaBrowser.strategies.cjs.map +1 -0
  184. package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts +9 -0
  185. package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts.map +1 -0
  186. package/dist/data/ai/ToolSchemaBrowser.strategies.js +54 -0
  187. package/dist/data/ai/ToolSchemaBrowser.strategies.js.map +1 -0
  188. package/dist/data/ai/ToolSchemaBrowser.tree.cjs +179 -0
  189. package/dist/data/ai/ToolSchemaBrowser.tree.cjs.map +1 -0
  190. package/dist/data/ai/ToolSchemaBrowser.tree.d.ts +20 -0
  191. package/dist/data/ai/ToolSchemaBrowser.tree.d.ts.map +1 -0
  192. package/dist/data/ai/ToolSchemaBrowser.tree.js +179 -0
  193. package/dist/data/ai/ToolSchemaBrowser.tree.js.map +1 -0
  194. package/dist/data/ai/index.d.ts +2 -2
  195. package/dist/data/ai/index.d.ts.map +1 -1
  196. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs +8 -28
  197. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs.map +1 -1
  198. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.d.ts.map +1 -1
  199. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js +9 -29
  200. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js.map +1 -1
  201. package/dist/data/ai/session-token-sizing.d.ts +32 -0
  202. package/dist/data/ai/session-token-sizing.d.ts.map +1 -0
  203. package/dist/data/ai/use-session-token-sizing.cjs +73 -0
  204. package/dist/data/ai/use-session-token-sizing.cjs.map +1 -0
  205. package/dist/data/ai/use-session-token-sizing.d.ts +21 -0
  206. package/dist/data/ai/use-session-token-sizing.d.ts.map +1 -0
  207. package/dist/data/ai/use-session-token-sizing.js +73 -0
  208. package/dist/data/ai/use-session-token-sizing.js.map +1 -0
  209. package/dist/data/call-graph/CallGraph.cjs +250 -0
  210. package/dist/data/call-graph/CallGraph.cjs.map +1 -0
  211. package/dist/data/call-graph/CallGraph.d.ts +69 -0
  212. package/dist/data/call-graph/CallGraph.d.ts.map +1 -0
  213. package/dist/data/call-graph/CallGraph.js +250 -0
  214. package/dist/data/call-graph/CallGraph.js.map +1 -0
  215. package/dist/data/call-graph/CallGraphGlyphs.cjs +39 -0
  216. package/dist/data/call-graph/CallGraphGlyphs.cjs.map +1 -0
  217. package/dist/data/call-graph/CallGraphGlyphs.d.ts +19 -0
  218. package/dist/data/call-graph/CallGraphGlyphs.d.ts.map +1 -0
  219. package/dist/data/call-graph/CallGraphGlyphs.js +39 -0
  220. package/dist/data/call-graph/CallGraphGlyphs.js.map +1 -0
  221. package/dist/data/call-graph/CallGraphMembers.cjs +50 -0
  222. package/dist/data/call-graph/CallGraphMembers.cjs.map +1 -0
  223. package/dist/data/call-graph/CallGraphMembers.d.ts +22 -0
  224. package/dist/data/call-graph/CallGraphMembers.d.ts.map +1 -0
  225. package/dist/data/call-graph/CallGraphMembers.js +50 -0
  226. package/dist/data/call-graph/CallGraphMembers.js.map +1 -0
  227. package/dist/data/call-graph/CallGraphParts.cjs +204 -0
  228. package/dist/data/call-graph/CallGraphParts.cjs.map +1 -0
  229. package/dist/data/call-graph/CallGraphParts.d.ts +44 -0
  230. package/dist/data/call-graph/CallGraphParts.d.ts.map +1 -0
  231. package/dist/data/call-graph/CallGraphParts.js +204 -0
  232. package/dist/data/call-graph/CallGraphParts.js.map +1 -0
  233. package/dist/data/call-graph/CallGraphToolbar.cjs +186 -0
  234. package/dist/data/call-graph/CallGraphToolbar.cjs.map +1 -0
  235. package/dist/data/call-graph/CallGraphToolbar.d.ts +45 -0
  236. package/dist/data/call-graph/CallGraphToolbar.d.ts.map +1 -0
  237. package/dist/data/call-graph/CallGraphToolbar.js +186 -0
  238. package/dist/data/call-graph/CallGraphToolbar.js.map +1 -0
  239. package/dist/data/call-graph/call-graph-exclude.cjs +75 -0
  240. package/dist/data/call-graph/call-graph-exclude.cjs.map +1 -0
  241. package/dist/data/call-graph/call-graph-exclude.d.ts +31 -0
  242. package/dist/data/call-graph/call-graph-exclude.d.ts.map +1 -0
  243. package/dist/data/call-graph/call-graph-exclude.js +75 -0
  244. package/dist/data/call-graph/call-graph-exclude.js.map +1 -0
  245. package/dist/data/call-graph/call-graph-labels.cjs +96 -0
  246. package/dist/data/call-graph/call-graph-labels.cjs.map +1 -0
  247. package/dist/data/call-graph/call-graph-labels.d.ts +53 -0
  248. package/dist/data/call-graph/call-graph-labels.d.ts.map +1 -0
  249. package/dist/data/call-graph/call-graph-labels.js +96 -0
  250. package/dist/data/call-graph/call-graph-labels.js.map +1 -0
  251. package/dist/data/call-graph/call-graph-model.cjs +161 -0
  252. package/dist/data/call-graph/call-graph-model.cjs.map +1 -0
  253. package/dist/data/call-graph/call-graph-model.d.ts +102 -0
  254. package/dist/data/call-graph/call-graph-model.d.ts.map +1 -0
  255. package/dist/data/call-graph/call-graph-model.js +161 -0
  256. package/dist/data/call-graph/call-graph-model.js.map +1 -0
  257. package/dist/data/call-graph/call-graph-vocabulary.cjs +177 -0
  258. package/dist/data/call-graph/call-graph-vocabulary.cjs.map +1 -0
  259. package/dist/data/call-graph/call-graph-vocabulary.d.ts +72 -0
  260. package/dist/data/call-graph/call-graph-vocabulary.d.ts.map +1 -0
  261. package/dist/data/call-graph/call-graph-vocabulary.js +177 -0
  262. package/dist/data/call-graph/call-graph-vocabulary.js.map +1 -0
  263. package/dist/data/call-graph/call-graph.fixtures.d.ts +63 -0
  264. package/dist/data/call-graph/call-graph.fixtures.d.ts.map +1 -0
  265. package/dist/data/call-graph/index.d.ts +7 -0
  266. package/dist/data/call-graph/index.d.ts.map +1 -0
  267. package/dist/data/call-graph/types.cjs +5 -0
  268. package/dist/data/call-graph/types.cjs.map +1 -0
  269. package/dist/data/call-graph/types.d.ts +135 -0
  270. package/dist/data/call-graph/types.d.ts.map +1 -0
  271. package/dist/data/call-graph/types.js +5 -0
  272. package/dist/data/call-graph/types.js.map +1 -0
  273. package/dist/data/call-graph/use-call-graph.cjs +93 -0
  274. package/dist/data/call-graph/use-call-graph.cjs.map +1 -0
  275. package/dist/data/call-graph/use-call-graph.d.ts +24 -0
  276. package/dist/data/call-graph/use-call-graph.d.ts.map +1 -0
  277. package/dist/data/call-graph/use-call-graph.js +93 -0
  278. package/dist/data/call-graph/use-call-graph.js.map +1 -0
  279. package/dist/data/chat/Chat.cjs +39 -15
  280. package/dist/data/chat/Chat.cjs.map +1 -1
  281. package/dist/data/chat/Chat.d.ts.map +1 -1
  282. package/dist/data/chat/Chat.fixtures.cjs +2 -2
  283. package/dist/data/chat/Chat.fixtures.cjs.map +1 -1
  284. package/dist/data/chat/Chat.fixtures.js +2 -2
  285. package/dist/data/chat/Chat.fixtures.js.map +1 -1
  286. package/dist/data/chat/Chat.js +40 -16
  287. package/dist/data/chat/Chat.js.map +1 -1
  288. package/dist/data/chat/ChatRuntimeToolbar.cjs +3 -6
  289. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  290. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  291. package/dist/data/chat/ChatRuntimeToolbar.js +3 -6
  292. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  293. package/dist/data/chat/ContextMeter.bar.cjs +5 -8
  294. package/dist/data/chat/ContextMeter.bar.cjs.map +1 -1
  295. package/dist/data/chat/ContextMeter.bar.d.ts +1 -1
  296. package/dist/data/chat/ContextMeter.bar.d.ts.map +1 -1
  297. package/dist/data/chat/ContextMeter.bar.js +5 -8
  298. package/dist/data/chat/ContextMeter.bar.js.map +1 -1
  299. package/dist/data/chat/ContextMeter.cjs +18 -19
  300. package/dist/data/chat/ContextMeter.cjs.map +1 -1
  301. package/dist/data/chat/ContextMeter.d.ts +1 -1
  302. package/dist/data/chat/ContextMeter.d.ts.map +1 -1
  303. package/dist/data/chat/ContextMeter.js +18 -19
  304. package/dist/data/chat/ContextMeter.js.map +1 -1
  305. package/dist/data/chat/Conversation.cjs +2 -1
  306. package/dist/data/chat/Conversation.cjs.map +1 -1
  307. package/dist/data/chat/Conversation.d.ts +4 -1
  308. package/dist/data/chat/Conversation.d.ts.map +1 -1
  309. package/dist/data/chat/Conversation.js +2 -1
  310. package/dist/data/chat/Conversation.js.map +1 -1
  311. package/dist/data/chat/Message.cjs +39 -12
  312. package/dist/data/chat/Message.cjs.map +1 -1
  313. package/dist/data/chat/Message.d.ts +1 -1
  314. package/dist/data/chat/Message.d.ts.map +1 -1
  315. package/dist/data/chat/Message.js +40 -13
  316. package/dist/data/chat/Message.js.map +1 -1
  317. package/dist/data/chat/ToolCall.cjs +60 -5
  318. package/dist/data/chat/ToolCall.cjs.map +1 -1
  319. package/dist/data/chat/ToolCall.d.ts +7 -2
  320. package/dist/data/chat/ToolCall.d.ts.map +1 -1
  321. package/dist/data/chat/ToolCall.js +60 -5
  322. package/dist/data/chat/ToolCall.js.map +1 -1
  323. package/dist/data/chat/approval.cjs.map +1 -1
  324. package/dist/data/chat/approval.d.ts +2 -2
  325. package/dist/data/chat/approval.d.ts.map +1 -1
  326. package/dist/data/chat/approval.js.map +1 -1
  327. package/dist/data/chat/tool-policy.cjs +59 -2
  328. package/dist/data/chat/tool-policy.cjs.map +1 -1
  329. package/dist/data/chat/tool-policy.d.ts +9 -0
  330. package/dist/data/chat/tool-policy.d.ts.map +1 -1
  331. package/dist/data/chat/tool-policy.js +59 -2
  332. package/dist/data/chat/tool-policy.js.map +1 -1
  333. package/dist/data/chat/types.cjs +6 -0
  334. package/dist/data/chat/types.cjs.map +1 -1
  335. package/dist/data/chat/types.d.ts +13 -4
  336. package/dist/data/chat/types.d.ts.map +1 -1
  337. package/dist/data/chat/types.js +7 -1
  338. package/dist/data/chat/types.js.map +1 -1
  339. package/dist/data/chat/usage-snapshot.cjs +11 -6
  340. package/dist/data/chat/usage-snapshot.cjs.map +1 -1
  341. package/dist/data/chat/usage-snapshot.d.ts +0 -1
  342. package/dist/data/chat/usage-snapshot.d.ts.map +1 -1
  343. package/dist/data/chat/usage-snapshot.js +11 -6
  344. package/dist/data/chat/usage-snapshot.js.map +1 -1
  345. package/dist/data/diagnostics/RenderedStackTrace.cjs +2 -1
  346. package/dist/data/diagnostics/RenderedStackTrace.cjs.map +1 -1
  347. package/dist/data/diagnostics/RenderedStackTrace.d.ts +3 -1
  348. package/dist/data/diagnostics/RenderedStackTrace.d.ts.map +1 -1
  349. package/dist/data/diagnostics/RenderedStackTrace.js +2 -1
  350. package/dist/data/diagnostics/RenderedStackTrace.js.map +1 -1
  351. package/dist/data/diagnostics/StackFrameRow.cjs +3 -3
  352. package/dist/data/diagnostics/StackFrameRow.cjs.map +1 -1
  353. package/dist/data/diagnostics/StackFrameRow.js +3 -3
  354. package/dist/data/diagnostics/StackFrameRow.js.map +1 -1
  355. package/dist/data/graph-columns-layout.cjs +26 -10
  356. package/dist/data/graph-columns-layout.cjs.map +1 -1
  357. package/dist/data/graph-columns-layout.d.ts +8 -0
  358. package/dist/data/graph-columns-layout.d.ts.map +1 -1
  359. package/dist/data/graph-columns-layout.js +26 -10
  360. package/dist/data/graph-columns-layout.js.map +1 -1
  361. package/dist/data/graph-diagram-model.cjs.map +1 -1
  362. package/dist/data/graph-diagram-model.d.ts +5 -0
  363. package/dist/data/graph-diagram-model.d.ts.map +1 -1
  364. package/dist/data/graph-diagram-model.js.map +1 -1
  365. package/dist/data/graph-edge-routing.cjs +9 -3
  366. package/dist/data/graph-edge-routing.cjs.map +1 -1
  367. package/dist/data/graph-edge-routing.d.ts +2 -0
  368. package/dist/data/graph-edge-routing.d.ts.map +1 -1
  369. package/dist/data/graph-edge-routing.js +9 -3
  370. package/dist/data/graph-edge-routing.js.map +1 -1
  371. package/dist/data/json-view/JsonSource.cjs +84 -0
  372. package/dist/data/json-view/JsonSource.cjs.map +1 -0
  373. package/dist/data/json-view/JsonSource.d.ts +7 -0
  374. package/dist/data/json-view/JsonSource.d.ts.map +1 -0
  375. package/dist/data/json-view/JsonSource.js +84 -0
  376. package/dist/data/json-view/JsonSource.js.map +1 -0
  377. package/dist/data/json-view/parse-prefix.cjs +132 -0
  378. package/dist/data/json-view/parse-prefix.cjs.map +1 -0
  379. package/dist/data/json-view/parse-prefix.d.ts +11 -0
  380. package/dist/data/json-view/parse-prefix.d.ts.map +1 -0
  381. package/dist/data/json-view/parse-prefix.js +132 -0
  382. package/dist/data/json-view/parse-prefix.js.map +1 -0
  383. package/dist/data/json-view/parse-source.cjs +62 -0
  384. package/dist/data/json-view/parse-source.cjs.map +1 -0
  385. package/dist/data/json-view/parse-source.d.ts +16 -0
  386. package/dist/data/json-view/parse-source.d.ts.map +1 -0
  387. package/dist/data/json-view/parse-source.js +62 -0
  388. package/dist/data/json-view/parse-source.js.map +1 -0
  389. package/dist/data/json-view/story-fixtures.d.ts +6 -0
  390. package/dist/data/json-view/story-fixtures.d.ts.map +1 -0
  391. package/dist/data/json-view/types.d.ts +14 -0
  392. package/dist/data/json-view/types.d.ts.map +1 -0
  393. package/dist/data/runtime/RuntimeBar.cjs +2 -5
  394. package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
  395. package/dist/data/runtime/RuntimeBar.d.ts +2 -4
  396. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
  397. package/dist/data/runtime/RuntimeBar.fields.cjs +2 -2
  398. package/dist/data/runtime/RuntimeBar.fields.cjs.map +1 -1
  399. package/dist/data/runtime/RuntimeBar.fields.js +2 -2
  400. package/dist/data/runtime/RuntimeBar.fields.js.map +1 -1
  401. package/dist/data/runtime/RuntimeBar.js +2 -5
  402. package/dist/data/runtime/RuntimeBar.js.map +1 -1
  403. package/dist/data/runtime/RuntimeBar.selection.cjs +4 -1
  404. package/dist/data/runtime/RuntimeBar.selection.cjs.map +1 -1
  405. package/dist/data/runtime/RuntimeBar.selection.d.ts.map +1 -1
  406. package/dist/data/runtime/RuntimeBar.selection.js +5 -2
  407. package/dist/data/runtime/RuntimeBar.selection.js.map +1 -1
  408. package/dist/data/runtime/RuntimeBarActions.cjs +1 -5
  409. package/dist/data/runtime/RuntimeBarActions.cjs.map +1 -1
  410. package/dist/data/runtime/RuntimeBarActions.d.ts +1 -1
  411. package/dist/data/runtime/RuntimeBarActions.d.ts.map +1 -1
  412. package/dist/data/runtime/RuntimeBarActions.js +1 -5
  413. package/dist/data/runtime/RuntimeBarActions.js.map +1 -1
  414. package/dist/data/runtime/RuntimeBarIdentity.cjs +6 -14
  415. package/dist/data/runtime/RuntimeBarIdentity.cjs.map +1 -1
  416. package/dist/data/runtime/RuntimeBarIdentity.d.ts +0 -1
  417. package/dist/data/runtime/RuntimeBarIdentity.d.ts.map +1 -1
  418. package/dist/data/runtime/RuntimeBarIdentity.js +6 -14
  419. package/dist/data/runtime/RuntimeBarIdentity.js.map +1 -1
  420. package/dist/data/runtime/RuntimeBarLayout.cjs +8 -27
  421. package/dist/data/runtime/RuntimeBarLayout.cjs.map +1 -1
  422. package/dist/data/runtime/RuntimeBarLayout.d.ts.map +1 -1
  423. package/dist/data/runtime/RuntimeBarLayout.js +8 -27
  424. package/dist/data/runtime/RuntimeBarLayout.js.map +1 -1
  425. package/dist/data/runtime/RuntimeBarSegment.cjs +1 -5
  426. package/dist/data/runtime/RuntimeBarSegment.cjs.map +1 -1
  427. package/dist/data/runtime/RuntimeBarSegment.d.ts.map +1 -1
  428. package/dist/data/runtime/RuntimeBarSegment.js +1 -5
  429. package/dist/data/runtime/RuntimeBarSegment.js.map +1 -1
  430. package/dist/data/runtime/use-runtime-bar-overflow.cjs +4 -10
  431. package/dist/data/runtime/use-runtime-bar-overflow.cjs.map +1 -1
  432. package/dist/data/runtime/use-runtime-bar-overflow.d.ts +1 -2
  433. package/dist/data/runtime/use-runtime-bar-overflow.d.ts.map +1 -1
  434. package/dist/data/runtime/use-runtime-bar-overflow.js +4 -10
  435. package/dist/data/runtime/use-runtime-bar-overflow.js.map +1 -1
  436. package/dist/data/test-runner/TestRunner.fixtures.d.ts +0 -20
  437. package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
  438. package/dist/data/test-runner/TestRunner.large-fixtures.d.ts +22 -0
  439. package/dist/data/test-runner/TestRunner.large-fixtures.d.ts.map +1 -0
  440. package/dist/data/use-pan-zoom.cjs +23 -10
  441. package/dist/data/use-pan-zoom.cjs.map +1 -1
  442. package/dist/data/use-pan-zoom.d.ts +16 -2
  443. package/dist/data/use-pan-zoom.d.ts.map +1 -1
  444. package/dist/data/use-pan-zoom.js +23 -10
  445. package/dist/data/use-pan-zoom.js.map +1 -1
  446. package/dist/data/version-info.cjs +3 -3
  447. package/dist/data/version-info.js +3 -3
  448. package/dist/data.cjs +28 -2
  449. package/dist/data.cjs.map +1 -1
  450. package/dist/data.d.ts +2 -0
  451. package/dist/data.d.ts.map +1 -1
  452. package/dist/data.js +26 -0
  453. package/dist/data.js.map +1 -1
  454. package/dist/index.cjs +30 -4
  455. package/dist/index.cjs.map +1 -1
  456. package/dist/index.js +26 -0
  457. package/dist/index.js.map +1 -1
  458. package/dist/layout/Workspace.cjs +13 -4
  459. package/dist/layout/Workspace.cjs.map +1 -1
  460. package/dist/layout/Workspace.d.ts +7 -2
  461. package/dist/layout/Workspace.d.ts.map +1 -1
  462. package/dist/layout/Workspace.js +13 -4
  463. package/dist/layout/Workspace.js.map +1 -1
  464. package/dist/lib/permission-strategies.cjs +71 -11
  465. package/dist/lib/permission-strategies.cjs.map +1 -1
  466. package/dist/lib/permission-strategies.d.ts +3 -0
  467. package/dist/lib/permission-strategies.d.ts.map +1 -1
  468. package/dist/lib/permission-strategies.js +71 -11
  469. package/dist/lib/permission-strategies.js.map +1 -1
  470. package/dist/styles.css +1 -1
  471. package/package.json +5 -3
  472. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs +0 -57
  473. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs.map +0 -1
  474. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts +0 -7
  475. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts.map +0 -1
  476. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js +0 -57
  477. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js.map +0 -1
  478. package/dist/data/runtime/RuntimeBar.context.cjs +0 -8
  479. package/dist/data/runtime/RuntimeBar.context.cjs.map +0 -1
  480. package/dist/data/runtime/RuntimeBar.context.d.ts +0 -2
  481. package/dist/data/runtime/RuntimeBar.context.d.ts.map +0 -1
  482. package/dist/data/runtime/RuntimeBar.context.js +0 -8
  483. package/dist/data/runtime/RuntimeBar.context.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.cjs","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart, ToolMeta, ToolResultRenderer } from \"./types\";\nimport { toolPartName } from \"./types\";\nimport { normalizeToolOutput } from \"./tool-render/normalize\";\nimport { useToolRenderRegistry } from \"./tool-render/context\";\nimport {\n defaultToolInputView,\n defaultToolOutputView,\n type ToolRenderBaseContext,\n} from \"./tool-render/defaults\";\nimport type { ToolRenderRegistry } from \"./tool-render/adapter\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n /** Respond to an approval request (only used when state is\n * `approval-requested`). Receives the approval id, the decision, and an\n * optional reason. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void)\n | undefined;\n renderToolResult?: ToolResultRenderer;\n /** Catalog entry for this tool. Defaults to the registry's catalog lookup. */\n tool?: ToolMeta | undefined;\n /** Renderer registry override. Defaults to the provided context registry. */\n registry?: ToolRenderRegistry | undefined;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<\n ToolState,\n { icon: StaticIconComponent; className: string }\n> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": {\n icon: UiCircleOutline,\n className: \"text-muted-foreground\",\n },\n \"input-available\": {\n icon: UiClock,\n className: \"text-muted-foreground animate-pulse\",\n },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name, status and compact input args, expanding to its input params and\n * (once available) output or error. Input and output rendering go through the\n * tool render registry, so a host can contribute domain views. Renders both\n * clicky `dynamic-tool` parts and typed `tool-<name>` parts, keyed off\n * `part.state`. */\nexport function ToolCall({\n part,\n defaultOpen = false,\n onApprove,\n renderToolResult,\n tool,\n registry: registryProp,\n className,\n}: ToolCallProps) {\n const needsApproval = part.state === \"approval-requested\";\n const [open, setOpen] = useState(defaultOpen || needsApproval);\n const contextRegistry = useToolRenderRegistry();\n const registry = registryProp ?? contextRegistry;\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n const meta = tool ?? registry.tool(name);\n\n // The transport double-encodes tool results as `{output: \"<json>\"}`; every\n // surface — including a host's renderToolResult — sees the unwrapped value.\n const normalized = normalizeToolOutput(\n part.state === \"output-available\" ? part.output : undefined,\n );\n const base: ToolRenderBaseContext = {\n part,\n toolName: name,\n tool: meta,\n state: part.state,\n input: part.input,\n output: normalized.value,\n isError: normalized.isError || part.state === \"output-error\",\n options: registry.options,\n };\n\n const inputView = defaultToolInputView(base);\n // The header keeps the tool name in its own element; a summary renders beside\n // it (ToolCall.test.tsx matches the name by exact text).\n const summary = registry.resolveSummary({ ...base, defaultView: null });\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n {!open && summary ? (\n <span className=\"min-w-0 flex-1 truncate text-xs\">{summary}</span>\n ) : null}\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\n \"size-3 shrink-0 transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n\n {open && (\n <div data-slot=\"tool-call-details\" className=\"space-y-1 pl-4 pt-0.5\">\n {/* An approval-requested call force-opens, so this params table is\n what the user reads before approving a write. */}\n {registry.resolveInput({ ...base, defaultView: inputView }) ??\n inputView}\n <ToolOutput\n part={part}\n base={base}\n registry={registry}\n output={normalized.value}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n </div>\n )}\n\n {needsApproval && <ApprovalControls part={part} onApprove={onApprove} />}\n </div>\n );\n}\n\n/** Approve/Deny controls shown while a tool call awaits human approval. The\n * approval id comes from the part's `approval` envelope (AI SDK v6). */\nfunction ApprovalControls({\n part,\n onApprove,\n}: {\n part: AnyToolPart;\n onApprove: ToolCallProps[\"onApprove\"];\n}) {\n const approval = \"approval\" in part ? part.approval : undefined;\n if (!approval || !onApprove) return null;\n return (\n <div className=\"mt-1.5 flex items-center gap-2 pl-4\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => onApprove(approval.id, true)}\n >\n Approve\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => onApprove(approval.id, false)}\n >\n Deny\n </Button>\n </div>\n );\n}\n\n/** The output surface. Priority: the host's `renderToolResult` prop (the\n * pre-registry API, still supported), then a matching adapter, then the\n * built-in shape heuristics. */\nfunction ToolOutput({\n part,\n base,\n registry,\n output,\n renderToolResult,\n}: {\n part: AnyToolPart;\n base: ToolRenderBaseContext;\n registry: ToolRenderRegistry;\n output: unknown;\n renderToolResult?: ToolResultRenderer | undefined;\n}) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const hasOutput = part.state === \"output-available\" && output !== undefined;\n if (!hasOutput && errorText === undefined) {\n return null;\n }\n\n const defaultView: ReactNode = hasOutput ? defaultToolOutputView(base) : null;\n\n const custom = hasOutput\n ? renderToolResult?.({ part, toolName: base.toolName, output })\n : null;\n const resolved = hasOutput\n ? registry.resolveOutput({ ...base, defaultView })\n : null;\n\n return (\n <div\n className={cn(\n \"overflow-x-auto text-xs\",\n errorText ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {errorText !== undefined && <div>{errorText}</div>}\n {custom ?? resolved ?? defaultView}\n </div>\n );\n}\n"],"names":["UiClock","UiCheck","UiCircleOutline","UiCircleX","useState","useToolRenderRegistry","toolPartName","normalizeToolOutput","defaultToolInputView","cn","jsxs","jsx","Icon","UiWrench","UiChevronDown","Button","defaultToolOutputView"],"mappings":"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"}
1
+ {"version":3,"file":"ToolCall.cjs","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart, ToolMeta, ToolResultRenderer } from \"./types\";\nimport { toolPartName } from \"./types\";\nimport { normalizeToolOutput } from \"./tool-render/normalize\";\nimport { useToolRenderRegistry } from \"./tool-render/context\";\nimport {\n defaultToolInputView,\n defaultToolOutputView,\n type ToolRenderBaseContext,\n} from \"./tool-render/defaults\";\nimport type { ToolRenderRegistry } from \"./tool-render/adapter\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n /** Respond to an approval request (only used when state is\n * `approval-requested`). Receives the approval id, the decision, and an\n * optional reason. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void | Promise<unknown>)\n | undefined;\n renderToolResult?: ToolResultRenderer;\n /** Catalog entry for this tool. Defaults to the registry's catalog lookup. */\n tool?: ToolMeta | undefined;\n /** Renderer registry override. Defaults to the provided context registry. */\n registry?: ToolRenderRegistry | undefined;\n /** Calls made by the subagent this call spawned (an Agent/Task call), nested\n * beneath it. A background subagent keeps calling after its parent returns. */\n subcalls?: AnyToolPart[] | undefined;\n /** Descendants grouped by the call that spawned them. */\n subcallsByParent?: ReadonlyMap<string, AnyToolPart[]> | undefined;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<\n ToolState,\n { icon: StaticIconComponent; className: string }\n> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": {\n icon: UiCircleOutline,\n className: \"text-muted-foreground\",\n },\n \"input-available\": {\n icon: UiClock,\n className: \"text-muted-foreground animate-pulse\",\n },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name, status and compact input args, expanding to its input params and\n * (once available) output or error. Input and output rendering go through the\n * tool render registry, so a host can contribute domain views. Renders both\n * clicky `dynamic-tool` parts and typed `tool-<name>` parts, keyed off\n * `part.state`. */\nexport function ToolCall({\n part,\n defaultOpen = false,\n onApprove,\n renderToolResult,\n tool,\n registry: registryProp,\n subcalls = [],\n subcallsByParent,\n className,\n}: ToolCallProps) {\n const needsApproval = part.state === \"approval-requested\";\n const [userOpen, setOpen] = useState(defaultOpen || needsApproval);\n // A nested approval must stay reachable, so it holds its parent open.\n const open =\n userOpen || needsApproval || hasPendingApproval(subcalls, subcallsByParent);\n const contextRegistry = useToolRenderRegistry();\n const registry = registryProp ?? contextRegistry;\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n const meta = tool ?? registry.tool(name);\n\n // The transport double-encodes tool results as `{output: \"<json>\"}`; every\n // surface — including a host's renderToolResult — sees the unwrapped value.\n const normalized = normalizeToolOutput(\n part.state === \"output-available\" ? part.output : undefined,\n );\n const base: ToolRenderBaseContext = {\n part,\n toolName: name,\n tool: meta,\n state: part.state,\n input: part.input,\n output: normalized.value,\n isError: normalized.isError || part.state === \"output-error\",\n options: registry.options,\n };\n\n const inputView = defaultToolInputView(base);\n // The header keeps the tool name in its own element; a summary renders beside\n // it (ToolCall.test.tsx matches the name by exact text).\n const summary = registry.resolveSummary({ ...base, defaultView: null });\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n {subcalls.length > 0 ? (\n <span className=\"shrink-0 text-xs\">{subcallsLabel(subcalls)}</span>\n ) : null}\n {!open && summary ? (\n <span className=\"min-w-0 flex-1 truncate text-xs\">{summary}</span>\n ) : null}\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\n \"size-3 shrink-0 transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n\n {open && (\n <div data-slot=\"tool-call-details\" className=\"space-y-1 pl-4 pt-0.5\">\n {/* An approval-requested call force-opens, so this params table is\n what the user reads before approving a write. */}\n {registry.resolveInput({ ...base, defaultView: inputView }) ??\n inputView}\n <ToolOutput\n part={part}\n base={base}\n registry={registry}\n output={normalized.value}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n {subcalls.length > 0 && (\n <div\n data-slot=\"tool-call-subcalls\"\n className=\"border-l border-border pl-2\"\n >\n {subcalls.map((call) => (\n <ToolCall\n key={call.toolCallId}\n part={call}\n subcalls={subcallsByParent?.get(call.toolCallId)}\n subcallsByParent={subcallsByParent}\n onApprove={onApprove}\n registry={registry}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {needsApproval && <ApprovalControls part={part} onApprove={onApprove} />}\n </div>\n );\n}\n\nfunction hasPendingApproval(\n calls: AnyToolPart[],\n grouped: ToolCallProps[\"subcallsByParent\"],\n): boolean {\n return calls.some(\n (call) => call.state === \"approval-requested\" ||\n hasPendingApproval(grouped?.get(call.toolCallId) ?? [], grouped),\n );\n}\n\nfunction subcallsLabel(subcalls: AnyToolPart[]): string {\n const running = subcalls.filter(\n (call) => call.state === \"input-streaming\" || call.state === \"input-available\",\n ).length;\n const count = `${subcalls.length} ${subcalls.length === 1 ? \"call\" : \"calls\"}`;\n return running > 0 ? `${count} · ${running} running` : count;\n}\n\n/** Approve/Deny controls shown while a tool call awaits human approval. The\n * approval id comes from the part's `approval` envelope (AI SDK v6). While a\n * returned decision promise is in flight the clicked button shows progress\n * and both are disabled. */\nfunction ApprovalControls({\n part,\n onApprove,\n}: {\n part: AnyToolPart;\n onApprove: ToolCallProps[\"onApprove\"];\n}) {\n const [pending, setPending] = useState<\"approve\" | \"deny\">();\n const [error, setError] = useState<string>();\n const approval = \"approval\" in part ? part.approval : undefined;\n if (!approval || !onApprove) return null;\n const decide = async (approved: boolean) => {\n setPending(approved ? \"approve\" : \"deny\");\n setError(undefined);\n try {\n await onApprove(approval.id, approved);\n } catch (cause) {\n setError(\n `Cannot ${approved ? \"approve\" : \"deny\"} tool call: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n } finally {\n setPending(undefined);\n }\n };\n return (\n <div className=\"mt-1.5 flex flex-wrap items-center gap-2 pl-4\">\n <Button\n type=\"button\"\n size=\"sm\"\n loading={pending === \"approve\"}\n disabled={pending !== undefined}\n onClick={() => void decide(true)}\n >\n Approve\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n loading={pending === \"deny\"}\n disabled={pending !== undefined}\n onClick={() => void decide(false)}\n >\n Deny\n </Button>\n {error && (\n <div role=\"alert\" className=\"w-full text-xs text-destructive\">{error}</div>\n )}\n </div>\n );\n}\n\n/** The output surface. Priority: the host's `renderToolResult` prop (the\n * pre-registry API, still supported), then a matching adapter, then the\n * built-in shape heuristics. */\nfunction ToolOutput({\n part,\n base,\n registry,\n output,\n renderToolResult,\n}: {\n part: AnyToolPart;\n base: ToolRenderBaseContext;\n registry: ToolRenderRegistry;\n output: unknown;\n renderToolResult?: ToolResultRenderer | undefined;\n}) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const hasOutput = part.state === \"output-available\" && output !== undefined;\n if (!hasOutput && errorText === undefined) {\n return null;\n }\n\n const defaultView: ReactNode = hasOutput ? defaultToolOutputView(base) : null;\n\n const custom = hasOutput\n ? renderToolResult?.({ part, toolName: base.toolName, output })\n : null;\n const resolved = hasOutput\n ? registry.resolveOutput({ ...base, defaultView })\n : null;\n\n return (\n <div\n className={cn(\n \"overflow-x-auto text-xs\",\n errorText ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {errorText !== undefined && <div>{errorText}</div>}\n {custom ?? resolved ?? defaultView}\n </div>\n );\n}\n"],"names":["UiClock","UiCheck","UiCircleOutline","UiCircleX","useState","useToolRenderRegistry","toolPartName","normalizeToolOutput","defaultToolInputView","cn","jsxs","jsx","Icon","UiWrench","UiChevronDown","Button","defaultToolOutputView"],"mappings":"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"}
@@ -8,12 +8,17 @@ export type ToolCallProps = {
8
8
  /** Respond to an approval request (only used when state is
9
9
  * `approval-requested`). Receives the approval id, the decision, and an
10
10
  * optional reason. */
11
- onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void) | undefined;
11
+ onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void | Promise<unknown>) | undefined;
12
12
  renderToolResult?: ToolResultRenderer;
13
13
  /** Catalog entry for this tool. Defaults to the registry's catalog lookup. */
14
14
  tool?: ToolMeta | undefined;
15
15
  /** Renderer registry override. Defaults to the provided context registry. */
16
16
  registry?: ToolRenderRegistry | undefined;
17
+ /** Calls made by the subagent this call spawned (an Agent/Task call), nested
18
+ * beneath it. A background subagent keeps calling after its parent returns. */
19
+ subcalls?: AnyToolPart[] | undefined;
20
+ /** Descendants grouped by the call that spawned them. */
21
+ subcallsByParent?: ReadonlyMap<string, AnyToolPart[]> | undefined;
17
22
  className?: string;
18
23
  };
19
24
  /** Generic display of a single AI tool call: a collapsible header showing the
@@ -22,5 +27,5 @@ export type ToolCallProps = {
22
27
  * tool render registry, so a host can contribute domain views. Renders both
23
28
  * clicky `dynamic-tool` parts and typed `tool-<name>` parts, keyed off
24
29
  * `part.state`. */
25
- export declare function ToolCall({ part, defaultOpen, onApprove, renderToolResult, tool, registry: registryProp, className, }: ToolCallProps): import("react").JSX.Element;
30
+ export declare function ToolCall({ part, defaultOpen, onApprove, renderToolResult, tool, registry: registryProp, subcalls, subcallsByParent, className, }: ToolCallProps): import("react").JSX.Element;
26
31
  //# sourceMappingURL=ToolCall.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.d.ts","sourceRoot":"","sources":["../../../src/data/chat/ToolCall.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AASzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,MAAM,aAAa,GAAG;IAC1B,kEAAkE;IAClE,IAAI,EAAE,WAAW,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;2BAEuB;IACvB,SAAS,CAAC,EACN,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAClE,SAAS,CAAC;IACd,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAiCF;;;;;oBAKoB;AACpB,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,WAAmB,EACnB,SAAS,EACT,gBAAgB,EAChB,IAAI,EACJ,QAAQ,EAAE,YAAY,EACtB,SAAS,GACV,EAAE,aAAa,+BA8Ef"}
1
+ {"version":3,"file":"ToolCall.d.ts","sourceRoot":"","sources":["../../../src/data/chat/ToolCall.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AASzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,MAAM,aAAa,GAAG;IAC1B,kEAAkE;IAClE,IAAI,EAAE,WAAW,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;2BAEuB;IACvB,SAAS,CAAC,EACN,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,GACrF,SAAS,CAAC;IACd,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC1C;oFACgF;IAChF,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACrC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,GAAG,SAAS,CAAC;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAiCF;;;;;oBAKoB;AACpB,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,WAAmB,EACnB,SAAS,EACT,gBAAgB,EAChB,IAAI,EACJ,QAAQ,EAAE,YAAY,EACtB,QAAa,EACb,gBAAgB,EAChB,SAAS,GACV,EAAE,aAAa,+BAsGf"}
@@ -44,10 +44,13 @@ function ToolCall({
44
44
  renderToolResult,
45
45
  tool,
46
46
  registry: registryProp,
47
+ subcalls = [],
48
+ subcallsByParent,
47
49
  className
48
50
  }) {
49
51
  const needsApproval = part.state === "approval-requested";
50
- const [open, setOpen] = useState(defaultOpen || needsApproval);
52
+ const [userOpen, setOpen] = useState(defaultOpen || needsApproval);
53
+ const open = userOpen || needsApproval || hasPendingApproval(subcalls, subcallsByParent);
51
54
  const contextRegistry = useToolRenderRegistry();
52
55
  const registry = registryProp ?? contextRegistry;
53
56
  const status = STATUS_ICON[part.state];
@@ -88,6 +91,7 @@ function ToolCall({
88
91
  className: cn("size-3 shrink-0", status.className)
89
92
  }
90
93
  ),
94
+ subcalls.length > 0 ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs", children: subcallsLabel(subcalls) }) : null,
91
95
  !open && summary ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-xs", children: summary }) : null
92
96
  ] }),
93
97
  /* @__PURE__ */ jsx(
@@ -114,24 +118,72 @@ function ToolCall({
114
118
  output: normalized.value,
115
119
  ...renderToolResult ? { renderToolResult } : {}
116
120
  }
121
+ ),
122
+ subcalls.length > 0 && /* @__PURE__ */ jsx(
123
+ "div",
124
+ {
125
+ "data-slot": "tool-call-subcalls",
126
+ className: "border-l border-border pl-2",
127
+ children: subcalls.map((call) => /* @__PURE__ */ jsx(
128
+ ToolCall,
129
+ {
130
+ part: call,
131
+ subcalls: subcallsByParent == null ? void 0 : subcallsByParent.get(call.toolCallId),
132
+ subcallsByParent,
133
+ onApprove,
134
+ registry,
135
+ ...renderToolResult ? { renderToolResult } : {}
136
+ },
137
+ call.toolCallId
138
+ ))
139
+ }
117
140
  )
118
141
  ] }),
119
142
  needsApproval && /* @__PURE__ */ jsx(ApprovalControls, { part, onApprove })
120
143
  ] });
121
144
  }
145
+ function hasPendingApproval(calls, grouped) {
146
+ return calls.some(
147
+ (call) => call.state === "approval-requested" || hasPendingApproval((grouped == null ? void 0 : grouped.get(call.toolCallId)) ?? [], grouped)
148
+ );
149
+ }
150
+ function subcallsLabel(subcalls) {
151
+ const running = subcalls.filter(
152
+ (call) => call.state === "input-streaming" || call.state === "input-available"
153
+ ).length;
154
+ const count = `${subcalls.length} ${subcalls.length === 1 ? "call" : "calls"}`;
155
+ return running > 0 ? `${count} · ${running} running` : count;
156
+ }
122
157
  function ApprovalControls({
123
158
  part,
124
159
  onApprove
125
160
  }) {
161
+ const [pending, setPending] = useState();
162
+ const [error, setError] = useState();
126
163
  const approval = "approval" in part ? part.approval : void 0;
127
164
  if (!approval || !onApprove) return null;
128
- return /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-2 pl-4", children: [
165
+ const decide = async (approved) => {
166
+ setPending(approved ? "approve" : "deny");
167
+ setError(void 0);
168
+ try {
169
+ await onApprove(approval.id, approved);
170
+ } catch (cause) {
171
+ setError(
172
+ `Cannot ${approved ? "approve" : "deny"} tool call: ${cause instanceof Error ? cause.message : String(cause)}`
173
+ );
174
+ } finally {
175
+ setPending(void 0);
176
+ }
177
+ };
178
+ return /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-2 pl-4", children: [
129
179
  /* @__PURE__ */ jsx(
130
180
  Button,
131
181
  {
132
182
  type: "button",
133
183
  size: "sm",
134
- onClick: () => onApprove(approval.id, true),
184
+ loading: pending === "approve",
185
+ disabled: pending !== void 0,
186
+ onClick: () => void decide(true),
135
187
  children: "Approve"
136
188
  }
137
189
  ),
@@ -141,10 +193,13 @@ function ApprovalControls({
141
193
  type: "button",
142
194
  size: "sm",
143
195
  variant: "outline",
144
- onClick: () => onApprove(approval.id, false),
196
+ loading: pending === "deny",
197
+ disabled: pending !== void 0,
198
+ onClick: () => void decide(false),
145
199
  children: "Deny"
146
200
  }
147
- )
201
+ ),
202
+ error && /* @__PURE__ */ jsx("div", { role: "alert", className: "w-full text-xs text-destructive", children: error })
148
203
  ] });
149
204
  }
150
205
  function ToolOutput({
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.js","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart, ToolMeta, ToolResultRenderer } from \"./types\";\nimport { toolPartName } from \"./types\";\nimport { normalizeToolOutput } from \"./tool-render/normalize\";\nimport { useToolRenderRegistry } from \"./tool-render/context\";\nimport {\n defaultToolInputView,\n defaultToolOutputView,\n type ToolRenderBaseContext,\n} from \"./tool-render/defaults\";\nimport type { ToolRenderRegistry } from \"./tool-render/adapter\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n /** Respond to an approval request (only used when state is\n * `approval-requested`). Receives the approval id, the decision, and an\n * optional reason. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void)\n | undefined;\n renderToolResult?: ToolResultRenderer;\n /** Catalog entry for this tool. Defaults to the registry's catalog lookup. */\n tool?: ToolMeta | undefined;\n /** Renderer registry override. Defaults to the provided context registry. */\n registry?: ToolRenderRegistry | undefined;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<\n ToolState,\n { icon: StaticIconComponent; className: string }\n> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": {\n icon: UiCircleOutline,\n className: \"text-muted-foreground\",\n },\n \"input-available\": {\n icon: UiClock,\n className: \"text-muted-foreground animate-pulse\",\n },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name, status and compact input args, expanding to its input params and\n * (once available) output or error. Input and output rendering go through the\n * tool render registry, so a host can contribute domain views. Renders both\n * clicky `dynamic-tool` parts and typed `tool-<name>` parts, keyed off\n * `part.state`. */\nexport function ToolCall({\n part,\n defaultOpen = false,\n onApprove,\n renderToolResult,\n tool,\n registry: registryProp,\n className,\n}: ToolCallProps) {\n const needsApproval = part.state === \"approval-requested\";\n const [open, setOpen] = useState(defaultOpen || needsApproval);\n const contextRegistry = useToolRenderRegistry();\n const registry = registryProp ?? contextRegistry;\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n const meta = tool ?? registry.tool(name);\n\n // The transport double-encodes tool results as `{output: \"<json>\"}`; every\n // surface — including a host's renderToolResult — sees the unwrapped value.\n const normalized = normalizeToolOutput(\n part.state === \"output-available\" ? part.output : undefined,\n );\n const base: ToolRenderBaseContext = {\n part,\n toolName: name,\n tool: meta,\n state: part.state,\n input: part.input,\n output: normalized.value,\n isError: normalized.isError || part.state === \"output-error\",\n options: registry.options,\n };\n\n const inputView = defaultToolInputView(base);\n // The header keeps the tool name in its own element; a summary renders beside\n // it (ToolCall.test.tsx matches the name by exact text).\n const summary = registry.resolveSummary({ ...base, defaultView: null });\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n {!open && summary ? (\n <span className=\"min-w-0 flex-1 truncate text-xs\">{summary}</span>\n ) : null}\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\n \"size-3 shrink-0 transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n\n {open && (\n <div data-slot=\"tool-call-details\" className=\"space-y-1 pl-4 pt-0.5\">\n {/* An approval-requested call force-opens, so this params table is\n what the user reads before approving a write. */}\n {registry.resolveInput({ ...base, defaultView: inputView }) ??\n inputView}\n <ToolOutput\n part={part}\n base={base}\n registry={registry}\n output={normalized.value}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n </div>\n )}\n\n {needsApproval && <ApprovalControls part={part} onApprove={onApprove} />}\n </div>\n );\n}\n\n/** Approve/Deny controls shown while a tool call awaits human approval. The\n * approval id comes from the part's `approval` envelope (AI SDK v6). */\nfunction ApprovalControls({\n part,\n onApprove,\n}: {\n part: AnyToolPart;\n onApprove: ToolCallProps[\"onApprove\"];\n}) {\n const approval = \"approval\" in part ? part.approval : undefined;\n if (!approval || !onApprove) return null;\n return (\n <div className=\"mt-1.5 flex items-center gap-2 pl-4\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => onApprove(approval.id, true)}\n >\n Approve\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => onApprove(approval.id, false)}\n >\n Deny\n </Button>\n </div>\n );\n}\n\n/** The output surface. Priority: the host's `renderToolResult` prop (the\n * pre-registry API, still supported), then a matching adapter, then the\n * built-in shape heuristics. */\nfunction ToolOutput({\n part,\n base,\n registry,\n output,\n renderToolResult,\n}: {\n part: AnyToolPart;\n base: ToolRenderBaseContext;\n registry: ToolRenderRegistry;\n output: unknown;\n renderToolResult?: ToolResultRenderer | undefined;\n}) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const hasOutput = part.state === \"output-available\" && output !== undefined;\n if (!hasOutput && errorText === undefined) {\n return null;\n }\n\n const defaultView: ReactNode = hasOutput ? defaultToolOutputView(base) : null;\n\n const custom = hasOutput\n ? renderToolResult?.({ part, toolName: base.toolName, output })\n : null;\n const resolved = hasOutput\n ? registry.resolveOutput({ ...base, defaultView })\n : null;\n\n return (\n <div\n className={cn(\n \"overflow-x-auto text-xs\",\n errorText ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {errorText !== undefined && <div>{errorText}</div>}\n {custom ?? resolved ?? defaultView}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolCall.js","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart, ToolMeta, ToolResultRenderer } from \"./types\";\nimport { toolPartName } from \"./types\";\nimport { normalizeToolOutput } from \"./tool-render/normalize\";\nimport { useToolRenderRegistry } from \"./tool-render/context\";\nimport {\n defaultToolInputView,\n defaultToolOutputView,\n type ToolRenderBaseContext,\n} from \"./tool-render/defaults\";\nimport type { ToolRenderRegistry } from \"./tool-render/adapter\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n /** Respond to an approval request (only used when state is\n * `approval-requested`). Receives the approval id, the decision, and an\n * optional reason. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void | Promise<unknown>)\n | undefined;\n renderToolResult?: ToolResultRenderer;\n /** Catalog entry for this tool. Defaults to the registry's catalog lookup. */\n tool?: ToolMeta | undefined;\n /** Renderer registry override. Defaults to the provided context registry. */\n registry?: ToolRenderRegistry | undefined;\n /** Calls made by the subagent this call spawned (an Agent/Task call), nested\n * beneath it. A background subagent keeps calling after its parent returns. */\n subcalls?: AnyToolPart[] | undefined;\n /** Descendants grouped by the call that spawned them. */\n subcallsByParent?: ReadonlyMap<string, AnyToolPart[]> | undefined;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<\n ToolState,\n { icon: StaticIconComponent; className: string }\n> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": {\n icon: UiCircleOutline,\n className: \"text-muted-foreground\",\n },\n \"input-available\": {\n icon: UiClock,\n className: \"text-muted-foreground animate-pulse\",\n },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name, status and compact input args, expanding to its input params and\n * (once available) output or error. Input and output rendering go through the\n * tool render registry, so a host can contribute domain views. Renders both\n * clicky `dynamic-tool` parts and typed `tool-<name>` parts, keyed off\n * `part.state`. */\nexport function ToolCall({\n part,\n defaultOpen = false,\n onApprove,\n renderToolResult,\n tool,\n registry: registryProp,\n subcalls = [],\n subcallsByParent,\n className,\n}: ToolCallProps) {\n const needsApproval = part.state === \"approval-requested\";\n const [userOpen, setOpen] = useState(defaultOpen || needsApproval);\n // A nested approval must stay reachable, so it holds its parent open.\n const open =\n userOpen || needsApproval || hasPendingApproval(subcalls, subcallsByParent);\n const contextRegistry = useToolRenderRegistry();\n const registry = registryProp ?? contextRegistry;\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n const meta = tool ?? registry.tool(name);\n\n // The transport double-encodes tool results as `{output: \"<json>\"}`; every\n // surface — including a host's renderToolResult — sees the unwrapped value.\n const normalized = normalizeToolOutput(\n part.state === \"output-available\" ? part.output : undefined,\n );\n const base: ToolRenderBaseContext = {\n part,\n toolName: name,\n tool: meta,\n state: part.state,\n input: part.input,\n output: normalized.value,\n isError: normalized.isError || part.state === \"output-error\",\n options: registry.options,\n };\n\n const inputView = defaultToolInputView(base);\n // The header keeps the tool name in its own element; a summary renders beside\n // it (ToolCall.test.tsx matches the name by exact text).\n const summary = registry.resolveSummary({ ...base, defaultView: null });\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n {subcalls.length > 0 ? (\n <span className=\"shrink-0 text-xs\">{subcallsLabel(subcalls)}</span>\n ) : null}\n {!open && summary ? (\n <span className=\"min-w-0 flex-1 truncate text-xs\">{summary}</span>\n ) : null}\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\n \"size-3 shrink-0 transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n\n {open && (\n <div data-slot=\"tool-call-details\" className=\"space-y-1 pl-4 pt-0.5\">\n {/* An approval-requested call force-opens, so this params table is\n what the user reads before approving a write. */}\n {registry.resolveInput({ ...base, defaultView: inputView }) ??\n inputView}\n <ToolOutput\n part={part}\n base={base}\n registry={registry}\n output={normalized.value}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n {subcalls.length > 0 && (\n <div\n data-slot=\"tool-call-subcalls\"\n className=\"border-l border-border pl-2\"\n >\n {subcalls.map((call) => (\n <ToolCall\n key={call.toolCallId}\n part={call}\n subcalls={subcallsByParent?.get(call.toolCallId)}\n subcallsByParent={subcallsByParent}\n onApprove={onApprove}\n registry={registry}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {needsApproval && <ApprovalControls part={part} onApprove={onApprove} />}\n </div>\n );\n}\n\nfunction hasPendingApproval(\n calls: AnyToolPart[],\n grouped: ToolCallProps[\"subcallsByParent\"],\n): boolean {\n return calls.some(\n (call) => call.state === \"approval-requested\" ||\n hasPendingApproval(grouped?.get(call.toolCallId) ?? [], grouped),\n );\n}\n\nfunction subcallsLabel(subcalls: AnyToolPart[]): string {\n const running = subcalls.filter(\n (call) => call.state === \"input-streaming\" || call.state === \"input-available\",\n ).length;\n const count = `${subcalls.length} ${subcalls.length === 1 ? \"call\" : \"calls\"}`;\n return running > 0 ? `${count} · ${running} running` : count;\n}\n\n/** Approve/Deny controls shown while a tool call awaits human approval. The\n * approval id comes from the part's `approval` envelope (AI SDK v6). While a\n * returned decision promise is in flight the clicked button shows progress\n * and both are disabled. */\nfunction ApprovalControls({\n part,\n onApprove,\n}: {\n part: AnyToolPart;\n onApprove: ToolCallProps[\"onApprove\"];\n}) {\n const [pending, setPending] = useState<\"approve\" | \"deny\">();\n const [error, setError] = useState<string>();\n const approval = \"approval\" in part ? part.approval : undefined;\n if (!approval || !onApprove) return null;\n const decide = async (approved: boolean) => {\n setPending(approved ? \"approve\" : \"deny\");\n setError(undefined);\n try {\n await onApprove(approval.id, approved);\n } catch (cause) {\n setError(\n `Cannot ${approved ? \"approve\" : \"deny\"} tool call: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n } finally {\n setPending(undefined);\n }\n };\n return (\n <div className=\"mt-1.5 flex flex-wrap items-center gap-2 pl-4\">\n <Button\n type=\"button\"\n size=\"sm\"\n loading={pending === \"approve\"}\n disabled={pending !== undefined}\n onClick={() => void decide(true)}\n >\n Approve\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n loading={pending === \"deny\"}\n disabled={pending !== undefined}\n onClick={() => void decide(false)}\n >\n Deny\n </Button>\n {error && (\n <div role=\"alert\" className=\"w-full text-xs text-destructive\">{error}</div>\n )}\n </div>\n );\n}\n\n/** The output surface. Priority: the host's `renderToolResult` prop (the\n * pre-registry API, still supported), then a matching adapter, then the\n * built-in shape heuristics. */\nfunction ToolOutput({\n part,\n base,\n registry,\n output,\n renderToolResult,\n}: {\n part: AnyToolPart;\n base: ToolRenderBaseContext;\n registry: ToolRenderRegistry;\n output: unknown;\n renderToolResult?: ToolResultRenderer | undefined;\n}) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const hasOutput = part.state === \"output-available\" && output !== undefined;\n if (!hasOutput && errorText === undefined) {\n return null;\n }\n\n const defaultView: ReactNode = hasOutput ? defaultToolOutputView(base) : null;\n\n const custom = hasOutput\n ? renderToolResult?.({ part, toolName: base.toolName, output })\n : null;\n const resolved = hasOutput\n ? registry.resolveOutput({ ...base, defaultView })\n : null;\n\n return (\n <div\n className={cn(\n \"overflow-x-auto text-xs\",\n errorText ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {errorText !== undefined && <div>{errorText}</div>}\n {custom ?? resolved ?? defaultView}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"approval.cjs","sources":["../../../src/data/chat/approval.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport type { ChatModelRuntime, ChatUsageBreakdown } from \"./types\";\n\nexport type CaptainChatContext = {\n usedTokens?: number;\n windowTokens?: number;\n freePercent: number;\n};\n\nexport type CaptainChatCost = {\n model?: string;\n inputCost?: number;\n outputCost?: number;\n reasoningCost?: number;\n cacheReadCost?: number;\n cacheWriteCost?: number;\n providerCostUSD?: number;\n};\n\nexport type CaptainChatSession = {\n id: string;\n revision?: number;\n messages: UIMessage[];\n providerSessionId?: string;\n runtime?: ChatModelRuntime;\n forkedFrom?: string;\n context?: CaptainChatContext;\n usage?: ChatUsageBreakdown;\n cost?: CaptainChatCost;\n backend?: string;\n executionMode?: string;\n model?: string;\n};\n\nexport type ToolApprovalDecision = {\n sessionsApi: string;\n sessionId: string;\n approvalId: string;\n approved: boolean;\n reason?: string;\n};\n\ntype SessionFetch = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport async function getChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to load this chat.\");\n }\n const response = await fetcher(sessionEndpoint(sessionsApi, sessionId), {\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw await responseError(\"Chat session request\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function forkChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to fork this chat.\");\n }\n const response = await fetcher(\n `${sessionEndpoint(sessionsApi, sessionId)}/fork`,\n {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n },\n );\n if (!response.ok) {\n throw await responseError(\"Fork chat session\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function postToolApproval(\n decision: ToolApprovalDecision,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!decision.sessionId.trim()) {\n throw new Error(\"A session id is required to resolve this tool approval.\");\n }\n const endpoint = `${sessionEndpoint(\n decision.sessionsApi,\n decision.sessionId,\n )}/approvals/${encodeURIComponent(decision.approvalId)}`;\n const response = await fetcher(endpoint, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n decision.reason\n ? { approved: decision.approved, reason: decision.reason }\n : { approved: decision.approved },\n ),\n });\n if (!response.ok) {\n throw await responseError(\"Tool approval\", response);\n }\n return parseSession(await response.json());\n}\n\nfunction sessionEndpoint(sessionsApi: string, sessionId: string): string {\n return `${stripTrailingSlashes(sessionsApi)}/${encodeURIComponent(sessionId)}`;\n}\n\n// Linear scan instead of `.replace(/\\/+$/, \"\")`: the regex backtracks\n// polynomially on caller-supplied base URLs with many trailing slashes.\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end--;\n return value.slice(0, end);\n}\n\nfunction parseSession(value: unknown): CaptainChatSession {\n if (\n typeof value !== \"object\" ||\n value === null ||\n !(\"id\" in value) ||\n typeof value.id !== \"string\"\n ) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n const messages = \"messages\" in value ? value.messages : [];\n if (!Array.isArray(messages)) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n return { ...value, messages } as CaptainChatSession;\n}\n\nasync function responseError(\n label: string,\n response: Response,\n): Promise<Error> {\n const detail = (await response.text()).trim();\n return new Error(\n `${label} failed with status ${response.status}${\n detail ? `: ${detail}` : \".\"\n }`,\n );\n}\n"],"names":[],"mappings":";;AA+CA,eAAsB,eACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM,QAAQ,gBAAgB,aAAa,SAAS,GAAG;AAAA,IACtE,SAAS,EAAE,QAAQ,mBAAA;AAAA,EAAmB,CACvC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,wBAAwB,QAAQ;AAAA,EAC5D;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,gBACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,gBAAgB,aAAa,SAAS,CAAC;AAAA,IAC1C;AAAA,MACE,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,mBAAA;AAAA,IAAmB;AAAA,EACxC;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,qBAAqB,QAAQ;AAAA,EACzD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,iBACpB,UACA,UAAwB,OACK;AAC7B,MAAI,CAAC,SAAS,UAAU,QAAQ;AAC9B,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,QAAM,WAAW,GAAG;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,CACV,cAAc,mBAAmB,SAAS,UAAU,CAAC;AACtD,QAAM,WAAW,MAAM,QAAQ,UAAU;AAAA,IACvC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,IAElB,MAAM,KAAK;AAAA,MACT,SAAS,SACL,EAAE,UAAU,SAAS,UAAU,QAAQ,SAAS,OAAA,IAChD,EAAE,UAAU,SAAS,SAAA;AAAA,IAAS;AAAA,EACpC,CACD;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,iBAAiB,QAAQ;AAAA,EACrD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,SAAS,gBAAgB,aAAqB,WAA2B;AACvE,SAAO,GAAG,qBAAqB,WAAW,CAAC,IAAI,mBAAmB,SAAS,CAAC;AAC9E;AAIA,SAAS,qBAAqB,OAAuB;AACnD,MAAI,MAAM,MAAM;AAChB,SAAO,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,IAAK;AAC1C,SAAO,MAAM,MAAM,GAAG,GAAG;AAC3B;AAEA,SAAS,aAAa,OAAoC;AACxD,MACE,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,QAAQ,UACV,OAAO,MAAM,OAAO,UACpB;AACA,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,QAAM,WAAW,cAAc,QAAQ,MAAM,WAAW,CAAA;AACxD,MAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC5B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO,EAAE,GAAG,OAAO,SAAA;AACrB;AAEA,eAAe,cACb,OACA,UACgB;AAChB,QAAM,UAAU,MAAM,SAAS,KAAA,GAAQ,KAAA;AACvC,SAAO,IAAI;AAAA,IACT,GAAG,KAAK,uBAAuB,SAAS,MAAM,GAC5C,SAAS,KAAK,MAAM,KAAK,GAC3B;AAAA,EAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"approval.cjs","sources":["../../../src/data/chat/approval.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport type { ChatModelRuntime, ChatUsageBreakdown } from \"./types\";\n\nexport type CaptainChatContext = {\n usedTokens: number;\n windowTokens: number;\n freePercent: number;\n};\n\nexport type CaptainChatCost = {\n model?: string;\n inputCost?: number;\n outputCost?: number;\n reasoningCost?: number;\n cacheReadCost?: number;\n cacheWriteCost?: number;\n providerCostUSD?: number;\n};\n\nexport type CaptainChatSession = {\n id: string;\n revision?: number;\n messages: UIMessage[];\n providerSessionId?: string;\n runtime?: ChatModelRuntime;\n forkedFrom?: string;\n context?: CaptainChatContext;\n usage?: ChatUsageBreakdown;\n cost?: CaptainChatCost;\n backend?: string;\n executionMode?: string;\n model?: string;\n};\n\nexport type ToolApprovalDecision = {\n sessionsApi: string;\n sessionId: string;\n approvalId: string;\n approved: boolean;\n reason?: string;\n};\n\ntype SessionFetch = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport async function getChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to load this chat.\");\n }\n const response = await fetcher(sessionEndpoint(sessionsApi, sessionId), {\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw await responseError(\"Chat session request\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function forkChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to fork this chat.\");\n }\n const response = await fetcher(\n `${sessionEndpoint(sessionsApi, sessionId)}/fork`,\n {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n },\n );\n if (!response.ok) {\n throw await responseError(\"Fork chat session\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function postToolApproval(\n decision: ToolApprovalDecision,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!decision.sessionId.trim()) {\n throw new Error(\"A session id is required to resolve this tool approval.\");\n }\n const endpoint = `${sessionEndpoint(\n decision.sessionsApi,\n decision.sessionId,\n )}/approvals/${encodeURIComponent(decision.approvalId)}`;\n const response = await fetcher(endpoint, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n decision.reason\n ? { approved: decision.approved, reason: decision.reason }\n : { approved: decision.approved },\n ),\n });\n if (!response.ok) {\n throw await responseError(\"Tool approval\", response);\n }\n return parseSession(await response.json());\n}\n\nfunction sessionEndpoint(sessionsApi: string, sessionId: string): string {\n return `${stripTrailingSlashes(sessionsApi)}/${encodeURIComponent(sessionId)}`;\n}\n\n// Linear scan instead of `.replace(/\\/+$/, \"\")`: the regex backtracks\n// polynomially on caller-supplied base URLs with many trailing slashes.\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end--;\n return value.slice(0, end);\n}\n\nfunction parseSession(value: unknown): CaptainChatSession {\n if (\n typeof value !== \"object\" ||\n value === null ||\n !(\"id\" in value) ||\n typeof value.id !== \"string\"\n ) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n const messages = \"messages\" in value ? value.messages : [];\n if (!Array.isArray(messages)) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n return { ...value, messages } as CaptainChatSession;\n}\n\nasync function responseError(\n label: string,\n response: Response,\n): Promise<Error> {\n const detail = (await response.text()).trim();\n return new Error(\n `${label} failed with status ${response.status}${\n detail ? `: ${detail}` : \".\"\n }`,\n );\n}\n"],"names":[],"mappings":";;AA+CA,eAAsB,eACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM,QAAQ,gBAAgB,aAAa,SAAS,GAAG;AAAA,IACtE,SAAS,EAAE,QAAQ,mBAAA;AAAA,EAAmB,CACvC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,wBAAwB,QAAQ;AAAA,EAC5D;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,gBACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,gBAAgB,aAAa,SAAS,CAAC;AAAA,IAC1C;AAAA,MACE,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,mBAAA;AAAA,IAAmB;AAAA,EACxC;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,qBAAqB,QAAQ;AAAA,EACzD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,iBACpB,UACA,UAAwB,OACK;AAC7B,MAAI,CAAC,SAAS,UAAU,QAAQ;AAC9B,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,QAAM,WAAW,GAAG;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,CACV,cAAc,mBAAmB,SAAS,UAAU,CAAC;AACtD,QAAM,WAAW,MAAM,QAAQ,UAAU;AAAA,IACvC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,IAElB,MAAM,KAAK;AAAA,MACT,SAAS,SACL,EAAE,UAAU,SAAS,UAAU,QAAQ,SAAS,OAAA,IAChD,EAAE,UAAU,SAAS,SAAA;AAAA,IAAS;AAAA,EACpC,CACD;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,iBAAiB,QAAQ;AAAA,EACrD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,SAAS,gBAAgB,aAAqB,WAA2B;AACvE,SAAO,GAAG,qBAAqB,WAAW,CAAC,IAAI,mBAAmB,SAAS,CAAC;AAC9E;AAIA,SAAS,qBAAqB,OAAuB;AACnD,MAAI,MAAM,MAAM;AAChB,SAAO,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,IAAK;AAC1C,SAAO,MAAM,MAAM,GAAG,GAAG;AAC3B;AAEA,SAAS,aAAa,OAAoC;AACxD,MACE,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,QAAQ,UACV,OAAO,MAAM,OAAO,UACpB;AACA,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,QAAM,WAAW,cAAc,QAAQ,MAAM,WAAW,CAAA;AACxD,MAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC5B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO,EAAE,GAAG,OAAO,SAAA;AACrB;AAEA,eAAe,cACb,OACA,UACgB;AAChB,QAAM,UAAU,MAAM,SAAS,KAAA,GAAQ,KAAA;AACvC,SAAO,IAAI;AAAA,IACT,GAAG,KAAK,uBAAuB,SAAS,MAAM,GAC5C,SAAS,KAAK,MAAM,KAAK,GAC3B;AAAA,EAAA;AAEJ;;;;"}
@@ -1,8 +1,8 @@
1
1
  import { UIMessage } from 'ai';
2
2
  import { ChatModelRuntime, ChatUsageBreakdown } from './types.js';
3
3
  export type CaptainChatContext = {
4
- usedTokens?: number;
5
- windowTokens?: number;
4
+ usedTokens: number;
5
+ windowTokens: number;
6
6
  freePercent: number;
7
7
  };
8
8
  export type CaptainChatCost = {
@@ -1 +1 @@
1
- {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/data/chat/approval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,YAAY,GAAG,CAClB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,YAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAW7B;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,YAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAe7B;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,YAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAwB7B"}
1
+ {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/data/chat/approval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,YAAY,GAAG,CAClB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,YAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAW7B;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,YAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAe7B;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,YAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAwB7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"approval.js","sources":["../../../src/data/chat/approval.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport type { ChatModelRuntime, ChatUsageBreakdown } from \"./types\";\n\nexport type CaptainChatContext = {\n usedTokens?: number;\n windowTokens?: number;\n freePercent: number;\n};\n\nexport type CaptainChatCost = {\n model?: string;\n inputCost?: number;\n outputCost?: number;\n reasoningCost?: number;\n cacheReadCost?: number;\n cacheWriteCost?: number;\n providerCostUSD?: number;\n};\n\nexport type CaptainChatSession = {\n id: string;\n revision?: number;\n messages: UIMessage[];\n providerSessionId?: string;\n runtime?: ChatModelRuntime;\n forkedFrom?: string;\n context?: CaptainChatContext;\n usage?: ChatUsageBreakdown;\n cost?: CaptainChatCost;\n backend?: string;\n executionMode?: string;\n model?: string;\n};\n\nexport type ToolApprovalDecision = {\n sessionsApi: string;\n sessionId: string;\n approvalId: string;\n approved: boolean;\n reason?: string;\n};\n\ntype SessionFetch = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport async function getChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to load this chat.\");\n }\n const response = await fetcher(sessionEndpoint(sessionsApi, sessionId), {\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw await responseError(\"Chat session request\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function forkChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to fork this chat.\");\n }\n const response = await fetcher(\n `${sessionEndpoint(sessionsApi, sessionId)}/fork`,\n {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n },\n );\n if (!response.ok) {\n throw await responseError(\"Fork chat session\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function postToolApproval(\n decision: ToolApprovalDecision,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!decision.sessionId.trim()) {\n throw new Error(\"A session id is required to resolve this tool approval.\");\n }\n const endpoint = `${sessionEndpoint(\n decision.sessionsApi,\n decision.sessionId,\n )}/approvals/${encodeURIComponent(decision.approvalId)}`;\n const response = await fetcher(endpoint, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n decision.reason\n ? { approved: decision.approved, reason: decision.reason }\n : { approved: decision.approved },\n ),\n });\n if (!response.ok) {\n throw await responseError(\"Tool approval\", response);\n }\n return parseSession(await response.json());\n}\n\nfunction sessionEndpoint(sessionsApi: string, sessionId: string): string {\n return `${stripTrailingSlashes(sessionsApi)}/${encodeURIComponent(sessionId)}`;\n}\n\n// Linear scan instead of `.replace(/\\/+$/, \"\")`: the regex backtracks\n// polynomially on caller-supplied base URLs with many trailing slashes.\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end--;\n return value.slice(0, end);\n}\n\nfunction parseSession(value: unknown): CaptainChatSession {\n if (\n typeof value !== \"object\" ||\n value === null ||\n !(\"id\" in value) ||\n typeof value.id !== \"string\"\n ) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n const messages = \"messages\" in value ? value.messages : [];\n if (!Array.isArray(messages)) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n return { ...value, messages } as CaptainChatSession;\n}\n\nasync function responseError(\n label: string,\n response: Response,\n): Promise<Error> {\n const detail = (await response.text()).trim();\n return new Error(\n `${label} failed with status ${response.status}${\n detail ? `: ${detail}` : \".\"\n }`,\n );\n}\n"],"names":[],"mappings":"AA+CA,eAAsB,eACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM,QAAQ,gBAAgB,aAAa,SAAS,GAAG;AAAA,IACtE,SAAS,EAAE,QAAQ,mBAAA;AAAA,EAAmB,CACvC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,wBAAwB,QAAQ;AAAA,EAC5D;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,gBACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,gBAAgB,aAAa,SAAS,CAAC;AAAA,IAC1C;AAAA,MACE,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,mBAAA;AAAA,IAAmB;AAAA,EACxC;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,qBAAqB,QAAQ;AAAA,EACzD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,iBACpB,UACA,UAAwB,OACK;AAC7B,MAAI,CAAC,SAAS,UAAU,QAAQ;AAC9B,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,QAAM,WAAW,GAAG;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,CACV,cAAc,mBAAmB,SAAS,UAAU,CAAC;AACtD,QAAM,WAAW,MAAM,QAAQ,UAAU;AAAA,IACvC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,IAElB,MAAM,KAAK;AAAA,MACT,SAAS,SACL,EAAE,UAAU,SAAS,UAAU,QAAQ,SAAS,OAAA,IAChD,EAAE,UAAU,SAAS,SAAA;AAAA,IAAS;AAAA,EACpC,CACD;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,iBAAiB,QAAQ;AAAA,EACrD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,SAAS,gBAAgB,aAAqB,WAA2B;AACvE,SAAO,GAAG,qBAAqB,WAAW,CAAC,IAAI,mBAAmB,SAAS,CAAC;AAC9E;AAIA,SAAS,qBAAqB,OAAuB;AACnD,MAAI,MAAM,MAAM;AAChB,SAAO,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,IAAK;AAC1C,SAAO,MAAM,MAAM,GAAG,GAAG;AAC3B;AAEA,SAAS,aAAa,OAAoC;AACxD,MACE,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,QAAQ,UACV,OAAO,MAAM,OAAO,UACpB;AACA,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,QAAM,WAAW,cAAc,QAAQ,MAAM,WAAW,CAAA;AACxD,MAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC5B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO,EAAE,GAAG,OAAO,SAAA;AACrB;AAEA,eAAe,cACb,OACA,UACgB;AAChB,QAAM,UAAU,MAAM,SAAS,KAAA,GAAQ,KAAA;AACvC,SAAO,IAAI;AAAA,IACT,GAAG,KAAK,uBAAuB,SAAS,MAAM,GAC5C,SAAS,KAAK,MAAM,KAAK,GAC3B;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"approval.js","sources":["../../../src/data/chat/approval.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport type { ChatModelRuntime, ChatUsageBreakdown } from \"./types\";\n\nexport type CaptainChatContext = {\n usedTokens: number;\n windowTokens: number;\n freePercent: number;\n};\n\nexport type CaptainChatCost = {\n model?: string;\n inputCost?: number;\n outputCost?: number;\n reasoningCost?: number;\n cacheReadCost?: number;\n cacheWriteCost?: number;\n providerCostUSD?: number;\n};\n\nexport type CaptainChatSession = {\n id: string;\n revision?: number;\n messages: UIMessage[];\n providerSessionId?: string;\n runtime?: ChatModelRuntime;\n forkedFrom?: string;\n context?: CaptainChatContext;\n usage?: ChatUsageBreakdown;\n cost?: CaptainChatCost;\n backend?: string;\n executionMode?: string;\n model?: string;\n};\n\nexport type ToolApprovalDecision = {\n sessionsApi: string;\n sessionId: string;\n approvalId: string;\n approved: boolean;\n reason?: string;\n};\n\ntype SessionFetch = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport async function getChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to load this chat.\");\n }\n const response = await fetcher(sessionEndpoint(sessionsApi, sessionId), {\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw await responseError(\"Chat session request\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function forkChatSession(\n sessionsApi: string,\n sessionId: string,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!sessionId.trim()) {\n throw new Error(\"A session id is required to fork this chat.\");\n }\n const response = await fetcher(\n `${sessionEndpoint(sessionsApi, sessionId)}/fork`,\n {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n },\n );\n if (!response.ok) {\n throw await responseError(\"Fork chat session\", response);\n }\n return parseSession(await response.json());\n}\n\nexport async function postToolApproval(\n decision: ToolApprovalDecision,\n fetcher: SessionFetch = fetch,\n): Promise<CaptainChatSession> {\n if (!decision.sessionId.trim()) {\n throw new Error(\"A session id is required to resolve this tool approval.\");\n }\n const endpoint = `${sessionEndpoint(\n decision.sessionsApi,\n decision.sessionId,\n )}/approvals/${encodeURIComponent(decision.approvalId)}`;\n const response = await fetcher(endpoint, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n decision.reason\n ? { approved: decision.approved, reason: decision.reason }\n : { approved: decision.approved },\n ),\n });\n if (!response.ok) {\n throw await responseError(\"Tool approval\", response);\n }\n return parseSession(await response.json());\n}\n\nfunction sessionEndpoint(sessionsApi: string, sessionId: string): string {\n return `${stripTrailingSlashes(sessionsApi)}/${encodeURIComponent(sessionId)}`;\n}\n\n// Linear scan instead of `.replace(/\\/+$/, \"\")`: the regex backtracks\n// polynomially on caller-supplied base URLs with many trailing slashes.\nfunction stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") end--;\n return value.slice(0, end);\n}\n\nfunction parseSession(value: unknown): CaptainChatSession {\n if (\n typeof value !== \"object\" ||\n value === null ||\n !(\"id\" in value) ||\n typeof value.id !== \"string\"\n ) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n const messages = \"messages\" in value ? value.messages : [];\n if (!Array.isArray(messages)) {\n throw new Error(\"Captain chat session response is invalid.\");\n }\n return { ...value, messages } as CaptainChatSession;\n}\n\nasync function responseError(\n label: string,\n response: Response,\n): Promise<Error> {\n const detail = (await response.text()).trim();\n return new Error(\n `${label} failed with status ${response.status}${\n detail ? `: ${detail}` : \".\"\n }`,\n );\n}\n"],"names":[],"mappings":"AA+CA,eAAsB,eACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM,QAAQ,gBAAgB,aAAa,SAAS,GAAG;AAAA,IACtE,SAAS,EAAE,QAAQ,mBAAA;AAAA,EAAmB,CACvC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,wBAAwB,QAAQ;AAAA,EAC5D;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,gBACpB,aACA,WACA,UAAwB,OACK;AAC7B,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,gBAAgB,aAAa,SAAS,CAAC;AAAA,IAC1C;AAAA,MACE,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,mBAAA;AAAA,IAAmB;AAAA,EACxC;AAEF,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,qBAAqB,QAAQ;AAAA,EACzD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,eAAsB,iBACpB,UACA,UAAwB,OACK;AAC7B,MAAI,CAAC,SAAS,UAAU,QAAQ;AAC9B,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,QAAM,WAAW,GAAG;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,CACV,cAAc,mBAAmB,SAAS,UAAU,CAAC;AACtD,QAAM,WAAW,MAAM,QAAQ,UAAU;AAAA,IACvC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,IAElB,MAAM,KAAK;AAAA,MACT,SAAS,SACL,EAAE,UAAU,SAAS,UAAU,QAAQ,SAAS,OAAA,IAChD,EAAE,UAAU,SAAS,SAAA;AAAA,IAAS;AAAA,EACpC,CACD;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM,cAAc,iBAAiB,QAAQ;AAAA,EACrD;AACA,SAAO,aAAa,MAAM,SAAS,MAAM;AAC3C;AAEA,SAAS,gBAAgB,aAAqB,WAA2B;AACvE,SAAO,GAAG,qBAAqB,WAAW,CAAC,IAAI,mBAAmB,SAAS,CAAC;AAC9E;AAIA,SAAS,qBAAqB,OAAuB;AACnD,MAAI,MAAM,MAAM;AAChB,SAAO,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,IAAK;AAC1C,SAAO,MAAM,MAAM,GAAG,GAAG;AAC3B;AAEA,SAAS,aAAa,OAAoC;AACxD,MACE,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,QAAQ,UACV,OAAO,MAAM,OAAO,UACpB;AACA,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,QAAM,WAAW,cAAc,QAAQ,MAAM,WAAW,CAAA;AACxD,MAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC5B,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO,EAAE,GAAG,OAAO,SAAA;AACrB;AAEA,eAAe,cACb,OACA,UACgB;AAChB,QAAM,UAAU,MAAM,SAAS,KAAA,GAAQ,KAAA;AACvC,SAAO,IAAI;AAAA,IACT,GAAG,KAAK,uBAAuB,SAAS,MAAM,GAC5C,SAAS,KAAK,MAAM,KAAK,GAC3B;AAAA,EAAA;AAEJ;"}
@@ -94,10 +94,66 @@ function toolPolicyFromPreferences(prefs) {
94
94
  if (policy) policies.set(key, policy);
95
95
  }
96
96
  const ordered = [...policies.keys()];
97
- return [
97
+ return consolidateRules([
98
98
  ...ordered.map((key) => ({ group: key, policy: policies.get(key) })),
99
99
  ...ordered.map((key) => ({ name: key, policy: policies.get(key) }))
100
- ];
100
+ ]);
101
+ }
102
+ function exactSelection(rule) {
103
+ const facets = Object.keys(rule).filter(
104
+ (key) => key !== "policy" && rule[key] !== void 0
105
+ );
106
+ if (facets.length !== 1) return void 0;
107
+ const facet = facets[0];
108
+ if (facet !== "name" && facet !== "group") return void 0;
109
+ const patterns = rule[facet];
110
+ const values = typeof patterns === "string" ? [patterns] : [...patterns];
111
+ if (values.length === 0 || values.some((value) => value.includes("*"))) {
112
+ return void 0;
113
+ }
114
+ return { facet, values };
115
+ }
116
+ function consolidateRules(rules) {
117
+ const seen = /* @__PURE__ */ new Set();
118
+ const live = [...rules].reverse().flatMap((rule) => {
119
+ const exact = exactSelection(rule);
120
+ if (!exact) return [rule];
121
+ const values = exact.values.filter((value) => {
122
+ const key = `${exact.facet}\0${value.toLowerCase()}`;
123
+ if (seen.has(key)) return false;
124
+ seen.add(key);
125
+ return true;
126
+ });
127
+ return values.length > 0 ? [{ [exact.facet]: values, policy: rule.policy }] : [];
128
+ }).reverse();
129
+ const merged = [];
130
+ let run = /* @__PURE__ */ new Map();
131
+ let runFacet;
132
+ for (const rule of live) {
133
+ const exact = exactSelection(rule);
134
+ if ((exact == null ? void 0 : exact.facet) !== runFacet || !exact) {
135
+ run = /* @__PURE__ */ new Map();
136
+ runFacet = exact == null ? void 0 : exact.facet;
137
+ }
138
+ if (!exact) {
139
+ merged.push({ values: [], rule });
140
+ continue;
141
+ }
142
+ const bucket = run.get(rule.policy);
143
+ if (bucket) {
144
+ bucket.values.push(...exact.values);
145
+ continue;
146
+ }
147
+ const entry = { facet: exact.facet, values: [...exact.values], rule };
148
+ run.set(rule.policy, entry);
149
+ merged.push(entry);
150
+ }
151
+ return merged.map(
152
+ ({ facet, values, rule }) => facet ? {
153
+ [facet]: values.length === 1 ? values[0] : values,
154
+ policy: rule.policy
155
+ } : rule
156
+ );
101
157
  }
102
158
  function appendToolPolicy(earlier, later) {
103
159
  return [...earlier ?? [], ...later ?? []];
@@ -124,6 +180,7 @@ function normalizeToolPolicyRules(value) {
124
180
  return rules;
125
181
  }
126
182
  exports.appendToolPolicy = appendToolPolicy;
183
+ exports.consolidateRules = consolidateRules;
127
184
  exports.matchItems = matchItems;
128
185
  exports.matchesTool = matchesTool;
129
186
  exports.normalizeToolPolicyRules = normalizeToolPolicyRules;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-policy.cjs","sources":["../../../src/data/chat/tool-policy.ts"],"sourcesContent":["import type { ToolMeta, ToolPolicy } from \"./types\";\nimport { normalizeToolPolicy } from \"./types\";\n\n/** The client half of Captain's ordered tool-permission policy.\n *\n * A tool's authority is decided by an ordered rule list evaluated\n * last-match-wins: weakest rule first, strongest last. The layers this file\n * composes are the surface's rules (what the page the chat opened on declares)\n * followed by the user's own (what they toggled in the preferences popover), so\n * a toggle beats the surface and the surface beats the application's baseline —\n * which the server appends underneath both.\n *\n * The matching is a port of Go's `commons/collections.MatchItems`, and it is a\n * port rather than a re-interpretation on purpose: the same rule list is\n * evaluated on both sides of the wire — here to render what a tool will do, and\n * on the server to enforce it — and a client that disagreed would show a state\n * the request does not produce. */\n\n/** A glob pattern list. A bare string is one pattern, so a rule can be written\n * `{ group: \"provider.xero.*\" }` without list ceremony. */\nexport type MatchPatterns = string | string[];\n\n/** Which tools a rule applies to. Every declared facet must match (AND across\n * facets); within one facet the patterns are alternatives (OR). An undeclared\n * facet does not constrain. */\nexport type ToolMatch = {\n name?: MatchPatterns;\n group?: MatchPatterns;\n parent?: MatchPatterns;\n entity?: MatchPatterns;\n action?: MatchPatterns;\n verb?: MatchPatterns;\n method?: MatchPatterns;\n scope?: MatchPatterns;\n /** A declared hint requires the tool to declare the same hint with the same\n * value. An undeclared hint on the tool does NOT match: \"this tool never said\n * whether it is read-only\" and \"this tool said it is not\" are different\n * claims, and reading the first as the second is how an unannotated tool\n * would inherit a permissive rule. */\n readOnly?: boolean;\n destructive?: boolean;\n idempotent?: boolean;\n};\n\n/** One ordered rule: the tools it selects and the authority they get. */\nexport type PermissionRule = ToolMatch & { policy: ToolPolicy };\n\n/** The ordered rule list, evaluated last-match-wins. */\nexport type PermissionPolicy = PermissionRule[];\n\nconst MATCH_FACETS = [\n \"name\",\n \"group\",\n \"parent\",\n \"entity\",\n \"action\",\n \"verb\",\n \"method\",\n \"scope\",\n] as const;\n\n/** Reports whether `item` satisfies these patterns, following MatchItems:\n * `!` negates and takes precedence over any positive match, `*` wildcards a\n * prefix, suffix or the whole item, matching is case-insensitive, and one\n * string may carry comma-separated alternatives. An empty list matches\n * everything — an undeclared facet imposes no constraint. */\nexport function matchItems(\n item: string,\n patterns: MatchPatterns | undefined,\n): boolean {\n const normalized = normalizePatterns(patterns);\n if (normalized.length === 0) return true;\n // Exclusions are checked first so `!` wins however the rule was written:\n // [\"a*\", \"!abc\"] must reject \"abc\" rather than accept it on the wildcard.\n const sorted = [...normalized].sort(\n (a, b) => exclusionRank(a) - exclusionRank(b),\n );\n for (const pattern of sorted) {\n if (pattern.startsWith(\"!\")) {\n if (matchPattern(item, pattern.slice(1))) return false;\n continue;\n }\n if (matchPattern(item, pattern)) return true;\n }\n // Every pattern excluded and none of them matched, so the item is admitted.\n return sorted.every((pattern) => pattern.startsWith(\"!\"));\n}\n\nfunction normalizePatterns(patterns: MatchPatterns | undefined): string[] {\n if (patterns === undefined) return [];\n const list = typeof patterns === \"string\" ? [patterns] : patterns;\n const out: string[] = [];\n for (const raw of list) {\n if (typeof raw !== \"string\") continue;\n const parts = raw.split(\",\");\n for (const part of parts) {\n const trimmed = part.trim();\n if (trimmed === \"\" && parts.length > 1) continue;\n if (trimmed !== \"\") out.push(trimmed);\n }\n }\n return out;\n}\n\nfunction exclusionRank(pattern: string): number {\n if (pattern === \"!*\") return 0;\n return pattern.startsWith(\"!\") ? 1 : 2;\n}\n\nfunction matchPattern(item: string, pattern: string): boolean {\n if (pattern === \"*\") return true;\n const value = item.toLowerCase();\n const glob = pattern.toLowerCase();\n if (value === glob) return true;\n if (glob.startsWith(\"*\") && glob.endsWith(\"*\")) {\n if (value.includes(glob.slice(1, -1))) return true;\n }\n if (glob.startsWith(\"*\") && value.endsWith(glob.slice(1))) return true;\n if (glob.endsWith(\"*\") && value.startsWith(glob.slice(0, -1))) return true;\n return false;\n}\n\n/** Resolves the authority for one tool: the policy of the LAST rule that\n * matches it, or undefined when no rule does.\n *\n * Last, not first, because the list runs weakest to strongest — a user rule\n * appended after a surface rule is meant to win. A first-match-wins reading\n * would invert the whole contract. */\nexport function resolveToolPolicy(\n policy: PermissionPolicy | undefined,\n tool: ToolMeta,\n): ToolPolicy | undefined {\n let resolved: ToolPolicy | undefined;\n for (const rule of policy ?? []) {\n if (matchesTool(rule, tool)) resolved = rule.policy;\n }\n return resolved;\n}\n\nexport function matchesTool(match: ToolMatch, tool: ToolMeta): boolean {\n const facets: Record<(typeof MATCH_FACETS)[number], string> = {\n name: tool.name ?? \"\",\n group: tool.group ?? \"\",\n parent: tool.parent ?? \"\",\n entity: tool.entity ?? \"\",\n action: tool.action ?? \"\",\n verb: tool.verb ?? \"\",\n method: tool.method ?? \"\",\n scope: tool.scope ?? \"\",\n };\n for (const facet of MATCH_FACETS) {\n if (!matchItems(facets[facet], match[facet])) return false;\n }\n return (\n matchesHint(match.readOnly, tool.annotations?.readOnlyHint) &&\n matchesHint(match.destructive, tool.annotations?.destructiveHint) &&\n matchesHint(match.idempotent, tool.annotations?.idempotentHint)\n );\n}\n\nfunction matchesHint(want: boolean | undefined, have: boolean | undefined) {\n if (want === undefined) return true;\n return have !== undefined && have === want;\n}\n\n/** Lowers a flat tool→policy map into ordered rules, so the legacy shape and the\n * rule list share one evaluation path instead of two that can disagree.\n *\n * A key is ambiguous — it may name a tool or its group — so each key emits both\n * a group rule and a name rule, with every group rule placed before every name\n * rule. A key that names a group matches no tool name and vice versa, so the\n * ambiguity costs nothing; and where a key is both, the name rule comes later\n * and wins. That is exactly the precedence the popover needs, where a per-tool\n * toggle must beat the group toggle above it.\n *\n * Keys are sorted so the request body is stable: an unstable order would make\n * every render look like a changed request. */\nexport function toolPolicyFromPreferences(\n prefs: Record<string, ToolPolicy> | undefined,\n): PermissionPolicy {\n const keys = Object.keys(prefs ?? {})\n .filter((key) => key.trim() !== \"\")\n .sort();\n if (keys.length === 0) return [];\n const policies = new Map<string, ToolPolicy>();\n for (const key of keys) {\n const policy = normalizeToolPolicy(prefs?.[key]);\n if (policy) policies.set(key, policy);\n }\n const ordered = [...policies.keys()];\n return [\n ...ordered.map((key) => ({ group: key, policy: policies.get(key)! })),\n ...ordered.map((key) => ({ name: key, policy: policies.get(key)! })),\n ];\n}\n\n/** Appends `later` onto `earlier`, the later winning. Composition rather than\n * mutation, so one caller's user rules cannot leak into another's. */\nexport function appendToolPolicy(\n earlier: PermissionPolicy | undefined,\n later: PermissionPolicy | undefined,\n): PermissionPolicy {\n return [...(earlier ?? []), ...(later ?? [])];\n}\n\n/** Parses a rule list off the wire, dropping anything malformed rather than\n * letting it silently become the last word on every tool: a rule with no facet\n * matches everything, and being last-match-wins that is the one mistake with\n * unbounded reach. */\nexport function normalizeToolPolicyRules(value: unknown): PermissionPolicy {\n if (!Array.isArray(value)) return [];\n const rules: PermissionPolicy = [];\n for (const raw of value) {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) continue;\n const item = raw as Record<string, unknown>;\n const policy = normalizeToolPolicy(item.policy);\n if (!policy) continue;\n const match: ToolMatch = {};\n for (const facet of MATCH_FACETS) {\n const patterns = normalizePatterns(item[facet] as MatchPatterns);\n if (patterns.length > 0) match[facet] = patterns;\n }\n for (const hint of [\"readOnly\", \"destructive\", \"idempotent\"] as const) {\n if (typeof item[hint] === \"boolean\") match[hint] = item[hint] as boolean;\n }\n if (Object.keys(match).length === 0) continue;\n rules.push({ ...match, policy });\n }\n return rules;\n}\n"],"names":["normalizeToolPolicy"],"mappings":";;;AAkDA,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,SAAS,WACd,MACA,UACS;AACT,QAAM,aAAa,kBAAkB,QAAQ;AAC7C,MAAI,WAAW,WAAW,EAAG,QAAO;AAGpC,QAAM,SAAS,CAAC,GAAG,UAAU,EAAE;AAAA,IAC7B,CAAC,GAAG,MAAM,cAAc,CAAC,IAAI,cAAc,CAAC;AAAA,EAAA;AAE9C,aAAW,WAAW,QAAQ;AAC5B,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,UAAI,aAAa,MAAM,QAAQ,MAAM,CAAC,CAAC,EAAG,QAAO;AACjD;AAAA,IACF;AACA,QAAI,aAAa,MAAM,OAAO,EAAG,QAAO;AAAA,EAC1C;AAEA,SAAO,OAAO,MAAM,CAAC,YAAY,QAAQ,WAAW,GAAG,CAAC;AAC1D;AAEA,SAAS,kBAAkB,UAA+C;AACxE,MAAI,aAAa,OAAW,QAAO,CAAA;AACnC,QAAM,OAAO,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;AACzD,QAAM,MAAgB,CAAA;AACtB,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,SAAU;AAC7B,UAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,eAAW,QAAQ,OAAO;AACxB,YAAM,UAAU,KAAK,KAAA;AACrB,UAAI,YAAY,MAAM,MAAM,SAAS,EAAG;AACxC,UAAI,YAAY,GAAI,KAAI,KAAK,OAAO;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,SAAyB;AAC9C,MAAI,YAAY,KAAM,QAAO;AAC7B,SAAO,QAAQ,WAAW,GAAG,IAAI,IAAI;AACvC;AAEA,SAAS,aAAa,MAAc,SAA0B;AAC5D,MAAI,YAAY,IAAK,QAAO;AAC5B,QAAM,QAAQ,KAAK,YAAA;AACnB,QAAM,OAAO,QAAQ,YAAA;AACrB,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC9C,QAAI,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,EAAG,QAAO;AAAA,EAChD;AACA,MAAI,KAAK,WAAW,GAAG,KAAK,MAAM,SAAS,KAAK,MAAM,CAAC,CAAC,EAAG,QAAO;AAClE,MAAI,KAAK,SAAS,GAAG,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC,EAAG,QAAO;AACtE,SAAO;AACT;AAQO,SAAS,kBACd,QACA,MACwB;AACxB,MAAI;AACJ,aAAW,QAAQ,UAAU,IAAI;AAC/B,QAAI,YAAY,MAAM,IAAI,cAAc,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEO,SAAS,YAAY,OAAkB,MAAyB;;AACrE,QAAM,SAAwD;AAAA,IAC5D,MAAM,KAAK,QAAQ;AAAA,IACnB,OAAO,KAAK,SAAS;AAAA,IACrB,QAAQ,KAAK,UAAU;AAAA,IACvB,QAAQ,KAAK,UAAU;AAAA,IACvB,QAAQ,KAAK,UAAU;AAAA,IACvB,MAAM,KAAK,QAAQ;AAAA,IACnB,QAAQ,KAAK,UAAU;AAAA,IACvB,OAAO,KAAK,SAAS;AAAA,EAAA;AAEvB,aAAW,SAAS,cAAc;AAChC,QAAI,CAAC,WAAW,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC,EAAG,QAAO;AAAA,EACvD;AACA,SACE,YAAY,MAAM,WAAU,UAAK,gBAAL,mBAAkB,YAAY,KAC1D,YAAY,MAAM,cAAa,UAAK,gBAAL,mBAAkB,eAAe,KAChE,YAAY,MAAM,aAAY,UAAK,gBAAL,mBAAkB,cAAc;AAElE;AAEA,SAAS,YAAY,MAA2B,MAA2B;AACzE,MAAI,SAAS,OAAW,QAAO;AAC/B,SAAO,SAAS,UAAa,SAAS;AACxC;AAcO,SAAS,0BACd,OACkB;AAClB,QAAM,OAAO,OAAO,KAAK,SAAS,CAAA,CAAE,EACjC,OAAO,CAAC,QAAQ,IAAI,KAAA,MAAW,EAAE,EACjC,KAAA;AACH,MAAI,KAAK,WAAW,EAAG,QAAO,CAAA;AAC9B,QAAM,+BAAe,IAAA;AACrB,aAAW,OAAO,MAAM;AACtB,UAAM,SAASA,MAAAA,oBAAoB,+BAAQ,IAAI;AAC/C,QAAI,OAAQ,UAAS,IAAI,KAAK,MAAM;AAAA,EACtC;AACA,QAAM,UAAU,CAAC,GAAG,SAAS,MAAM;AACnC,SAAO;AAAA,IACL,GAAG,QAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,KAAK,QAAQ,SAAS,IAAI,GAAG,IAAK;AAAA,IACpE,GAAG,QAAQ,IAAI,CAAC,SAAS,EAAE,MAAM,KAAK,QAAQ,SAAS,IAAI,GAAG,IAAK;AAAA,EAAA;AAEvE;AAIO,SAAS,iBACd,SACA,OACkB;AAClB,SAAO,CAAC,GAAI,WAAW,CAAA,GAAK,GAAI,SAAS,CAAA,CAAG;AAC9C;AAMO,SAAS,yBAAyB,OAAkC;AACzE,MAAI,CAAC,MAAM,QAAQ,KAAK,UAAU,CAAA;AAClC,QAAM,QAA0B,CAAA;AAChC,aAAW,OAAO,OAAO;AACvB,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG;AAC3D,UAAM,OAAO;AACb,UAAM,SAASA,MAAAA,oBAAoB,KAAK,MAAM;AAC9C,QAAI,CAAC,OAAQ;AACb,UAAM,QAAmB,CAAA;AACzB,eAAW,SAAS,cAAc;AAChC,YAAM,WAAW,kBAAkB,KAAK,KAAK,CAAkB;AAC/D,UAAI,SAAS,SAAS,EAAG,OAAM,KAAK,IAAI;AAAA,IAC1C;AACA,eAAW,QAAQ,CAAC,YAAY,eAAe,YAAY,GAAY;AACrE,UAAI,OAAO,KAAK,IAAI,MAAM,UAAW,OAAM,IAAI,IAAI,KAAK,IAAI;AAAA,IAC9D;AACA,QAAI,OAAO,KAAK,KAAK,EAAE,WAAW,EAAG;AACrC,UAAM,KAAK,EAAE,GAAG,OAAO,QAAQ;AAAA,EACjC;AACA,SAAO;AACT;;;;;;;"}
1
+ {"version":3,"file":"tool-policy.cjs","sources":["../../../src/data/chat/tool-policy.ts"],"sourcesContent":["import type { ToolMeta, ToolPolicy } from \"./types\";\nimport { normalizeToolPolicy } from \"./types\";\n\n/** The client half of Captain's ordered tool-permission policy.\n *\n * A tool's authority is decided by an ordered rule list evaluated\n * last-match-wins: weakest rule first, strongest last. The layers this file\n * composes are the surface's rules (what the page the chat opened on declares)\n * followed by the user's own (what they toggled in the preferences popover), so\n * a toggle beats the surface and the surface beats the application's baseline —\n * which the server appends underneath both.\n *\n * The matching is a port of Go's `commons/collections.MatchItems`, and it is a\n * port rather than a re-interpretation on purpose: the same rule list is\n * evaluated on both sides of the wire — here to render what a tool will do, and\n * on the server to enforce it — and a client that disagreed would show a state\n * the request does not produce. */\n\n/** A glob pattern list. A bare string is one pattern, so a rule can be written\n * `{ group: \"provider.xero.*\" }` without list ceremony. */\nexport type MatchPatterns = string | string[];\n\n/** Which tools a rule applies to. Every declared facet must match (AND across\n * facets); within one facet the patterns are alternatives (OR). An undeclared\n * facet does not constrain. */\nexport type ToolMatch = {\n name?: MatchPatterns;\n group?: MatchPatterns;\n parent?: MatchPatterns;\n entity?: MatchPatterns;\n action?: MatchPatterns;\n verb?: MatchPatterns;\n method?: MatchPatterns;\n scope?: MatchPatterns;\n /** A declared hint requires the tool to declare the same hint with the same\n * value. An undeclared hint on the tool does NOT match: \"this tool never said\n * whether it is read-only\" and \"this tool said it is not\" are different\n * claims, and reading the first as the second is how an unannotated tool\n * would inherit a permissive rule. */\n readOnly?: boolean;\n destructive?: boolean;\n idempotent?: boolean;\n};\n\n/** One ordered rule: the tools it selects and the authority they get. */\nexport type PermissionRule = ToolMatch & { policy: ToolPolicy };\n\n/** The ordered rule list, evaluated last-match-wins. */\nexport type PermissionPolicy = PermissionRule[];\n\nconst MATCH_FACETS = [\n \"name\",\n \"group\",\n \"parent\",\n \"entity\",\n \"action\",\n \"verb\",\n \"method\",\n \"scope\",\n] as const;\n\n/** Reports whether `item` satisfies these patterns, following MatchItems:\n * `!` negates and takes precedence over any positive match, `*` wildcards a\n * prefix, suffix or the whole item, matching is case-insensitive, and one\n * string may carry comma-separated alternatives. An empty list matches\n * everything — an undeclared facet imposes no constraint. */\nexport function matchItems(\n item: string,\n patterns: MatchPatterns | undefined,\n): boolean {\n const normalized = normalizePatterns(patterns);\n if (normalized.length === 0) return true;\n // Exclusions are checked first so `!` wins however the rule was written:\n // [\"a*\", \"!abc\"] must reject \"abc\" rather than accept it on the wildcard.\n const sorted = [...normalized].sort(\n (a, b) => exclusionRank(a) - exclusionRank(b),\n );\n for (const pattern of sorted) {\n if (pattern.startsWith(\"!\")) {\n if (matchPattern(item, pattern.slice(1))) return false;\n continue;\n }\n if (matchPattern(item, pattern)) return true;\n }\n // Every pattern excluded and none of them matched, so the item is admitted.\n return sorted.every((pattern) => pattern.startsWith(\"!\"));\n}\n\nfunction normalizePatterns(patterns: MatchPatterns | undefined): string[] {\n if (patterns === undefined) return [];\n const list = typeof patterns === \"string\" ? [patterns] : patterns;\n const out: string[] = [];\n for (const raw of list) {\n if (typeof raw !== \"string\") continue;\n const parts = raw.split(\",\");\n for (const part of parts) {\n const trimmed = part.trim();\n if (trimmed === \"\" && parts.length > 1) continue;\n if (trimmed !== \"\") out.push(trimmed);\n }\n }\n return out;\n}\n\nfunction exclusionRank(pattern: string): number {\n if (pattern === \"!*\") return 0;\n return pattern.startsWith(\"!\") ? 1 : 2;\n}\n\nfunction matchPattern(item: string, pattern: string): boolean {\n if (pattern === \"*\") return true;\n const value = item.toLowerCase();\n const glob = pattern.toLowerCase();\n if (value === glob) return true;\n if (glob.startsWith(\"*\") && glob.endsWith(\"*\")) {\n if (value.includes(glob.slice(1, -1))) return true;\n }\n if (glob.startsWith(\"*\") && value.endsWith(glob.slice(1))) return true;\n if (glob.endsWith(\"*\") && value.startsWith(glob.slice(0, -1))) return true;\n return false;\n}\n\n/** Resolves the authority for one tool: the policy of the LAST rule that\n * matches it, or undefined when no rule does.\n *\n * Last, not first, because the list runs weakest to strongest — a user rule\n * appended after a surface rule is meant to win. A first-match-wins reading\n * would invert the whole contract. */\nexport function resolveToolPolicy(\n policy: PermissionPolicy | undefined,\n tool: ToolMeta,\n): ToolPolicy | undefined {\n let resolved: ToolPolicy | undefined;\n for (const rule of policy ?? []) {\n if (matchesTool(rule, tool)) resolved = rule.policy;\n }\n return resolved;\n}\n\nexport function matchesTool(match: ToolMatch, tool: ToolMeta): boolean {\n const facets: Record<(typeof MATCH_FACETS)[number], string> = {\n name: tool.name ?? \"\",\n group: tool.group ?? \"\",\n parent: tool.parent ?? \"\",\n entity: tool.entity ?? \"\",\n action: tool.action ?? \"\",\n verb: tool.verb ?? \"\",\n method: tool.method ?? \"\",\n scope: tool.scope ?? \"\",\n };\n for (const facet of MATCH_FACETS) {\n if (!matchItems(facets[facet], match[facet])) return false;\n }\n return (\n matchesHint(match.readOnly, tool.annotations?.readOnlyHint) &&\n matchesHint(match.destructive, tool.annotations?.destructiveHint) &&\n matchesHint(match.idempotent, tool.annotations?.idempotentHint)\n );\n}\n\nfunction matchesHint(want: boolean | undefined, have: boolean | undefined) {\n if (want === undefined) return true;\n return have !== undefined && have === want;\n}\n\n/** Lowers a flat tool→policy map into ordered rules, so the legacy shape and the\n * rule list share one evaluation path instead of two that can disagree.\n *\n * A key is ambiguous — it may name a tool or its group — so each key emits both\n * a group rule and a name rule, with every group rule placed before every name\n * rule. A key that names a group matches no tool name and vice versa, so the\n * ambiguity costs nothing; and where a key is both, the name rule comes later\n * and wins. That is exactly the precedence the popover needs, where a per-tool\n * toggle must beat the group toggle above it.\n *\n * Keys are sorted so the request body is stable: an unstable order would make\n * every render look like a changed request. */\nexport function toolPolicyFromPreferences(\n prefs: Record<string, ToolPolicy> | undefined,\n): PermissionPolicy {\n const keys = Object.keys(prefs ?? {})\n .filter((key) => key.trim() !== \"\")\n .sort();\n if (keys.length === 0) return [];\n const policies = new Map<string, ToolPolicy>();\n for (const key of keys) {\n const policy = normalizeToolPolicy(prefs?.[key]);\n if (policy) policies.set(key, policy);\n }\n const ordered = [...policies.keys()];\n return consolidateRules([\n ...ordered.map((key) => ({ group: key, policy: policies.get(key)! })),\n ...ordered.map((key) => ({ name: key, policy: policies.get(key)! })),\n ]);\n}\n\ntype ExactFacet = \"name\" | \"group\";\n\n/** The exact names or groups a rule selects by, when it selects by nothing\n * else. Wildcards are excluded: they can overlap anything. */\nfunction exactSelection(\n rule: PermissionRule,\n): { facet: ExactFacet; values: string[] } | undefined {\n const facets = Object.keys(rule).filter(\n (key) =>\n key !== \"policy\" && rule[key as keyof PermissionRule] !== undefined,\n );\n if (facets.length !== 1) return undefined;\n const facet = facets[0];\n if (facet !== \"name\" && facet !== \"group\") return undefined;\n const patterns = rule[facet]!;\n const values = typeof patterns === \"string\" ? [patterns] : [...patterns];\n if (values.length === 0 || values.some((value) => value.includes(\"*\"))) {\n return undefined;\n }\n return { facet, values };\n}\n\n/** Folds exact-name and exact-group rules that share an action into one\n * in-clause, so a list of per-tool toggles reads as a few strategies.\n *\n * Evaluation is last-match-wins, so this keeps behaviour identical: an exact\n * value's earlier occurrences are dropped (the later one already wins), and\n * values merge only within a contiguous run of exact rules on the same facet,\n * which are disjoint by construction. Any other rule ends the run, because\n * moving a value past it could change which rule matches last. */\nexport function consolidateRules(rules: PermissionPolicy): PermissionPolicy {\n const seen = new Set<string>();\n const live = [...rules]\n .reverse()\n .flatMap((rule): PermissionPolicy => {\n const exact = exactSelection(rule);\n if (!exact) return [rule];\n const values = exact.values.filter((value) => {\n const key = `${exact.facet}\\u0000${value.toLowerCase()}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n return values.length > 0\n ? [{ [exact.facet]: values, policy: rule.policy }]\n : [];\n })\n .reverse();\n\n const merged: Array<{\n facet?: ExactFacet;\n values: string[];\n rule: PermissionRule;\n }> = [];\n let run = new Map<ToolPolicy, (typeof merged)[number]>();\n let runFacet: ExactFacet | undefined;\n for (const rule of live) {\n const exact = exactSelection(rule);\n if (exact?.facet !== runFacet || !exact) {\n run = new Map();\n runFacet = exact?.facet;\n }\n if (!exact) {\n merged.push({ values: [], rule });\n continue;\n }\n const bucket = run.get(rule.policy);\n if (bucket) {\n bucket.values.push(...exact.values);\n continue;\n }\n const entry = { facet: exact.facet, values: [...exact.values], rule };\n run.set(rule.policy, entry);\n merged.push(entry);\n }\n return merged.map(({ facet, values, rule }) =>\n facet\n ? {\n [facet]: values.length === 1 ? values[0] : values,\n policy: rule.policy,\n }\n : rule,\n );\n}\n\n/** Appends `later` onto `earlier`, the later winning. Composition rather than\n * mutation, so one caller's user rules cannot leak into another's. */\nexport function appendToolPolicy(\n earlier: PermissionPolicy | undefined,\n later: PermissionPolicy | undefined,\n): PermissionPolicy {\n return [...(earlier ?? []), ...(later ?? [])];\n}\n\n/** Parses a rule list off the wire, dropping anything malformed rather than\n * letting it silently become the last word on every tool: a rule with no facet\n * matches everything, and being last-match-wins that is the one mistake with\n * unbounded reach. */\nexport function normalizeToolPolicyRules(value: unknown): PermissionPolicy {\n if (!Array.isArray(value)) return [];\n const rules: PermissionPolicy = [];\n for (const raw of value) {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) continue;\n const item = raw as Record<string, unknown>;\n const policy = normalizeToolPolicy(item.policy);\n if (!policy) continue;\n const match: ToolMatch = {};\n for (const facet of MATCH_FACETS) {\n const patterns = normalizePatterns(item[facet] as MatchPatterns);\n if (patterns.length > 0) match[facet] = patterns;\n }\n for (const hint of [\"readOnly\", \"destructive\", \"idempotent\"] as const) {\n if (typeof item[hint] === \"boolean\") match[hint] = item[hint] as boolean;\n }\n if (Object.keys(match).length === 0) continue;\n rules.push({ ...match, policy });\n }\n return rules;\n}\n"],"names":["normalizeToolPolicy"],"mappings":";;;AAkDA,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,SAAS,WACd,MACA,UACS;AACT,QAAM,aAAa,kBAAkB,QAAQ;AAC7C,MAAI,WAAW,WAAW,EAAG,QAAO;AAGpC,QAAM,SAAS,CAAC,GAAG,UAAU,EAAE;AAAA,IAC7B,CAAC,GAAG,MAAM,cAAc,CAAC,IAAI,cAAc,CAAC;AAAA,EAAA;AAE9C,aAAW,WAAW,QAAQ;AAC5B,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,UAAI,aAAa,MAAM,QAAQ,MAAM,CAAC,CAAC,EAAG,QAAO;AACjD;AAAA,IACF;AACA,QAAI,aAAa,MAAM,OAAO,EAAG,QAAO;AAAA,EAC1C;AAEA,SAAO,OAAO,MAAM,CAAC,YAAY,QAAQ,WAAW,GAAG,CAAC;AAC1D;AAEA,SAAS,kBAAkB,UAA+C;AACxE,MAAI,aAAa,OAAW,QAAO,CAAA;AACnC,QAAM,OAAO,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;AACzD,QAAM,MAAgB,CAAA;AACtB,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,SAAU;AAC7B,UAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,eAAW,QAAQ,OAAO;AACxB,YAAM,UAAU,KAAK,KAAA;AACrB,UAAI,YAAY,MAAM,MAAM,SAAS,EAAG;AACxC,UAAI,YAAY,GAAI,KAAI,KAAK,OAAO;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,SAAyB;AAC9C,MAAI,YAAY,KAAM,QAAO;AAC7B,SAAO,QAAQ,WAAW,GAAG,IAAI,IAAI;AACvC;AAEA,SAAS,aAAa,MAAc,SAA0B;AAC5D,MAAI,YAAY,IAAK,QAAO;AAC5B,QAAM,QAAQ,KAAK,YAAA;AACnB,QAAM,OAAO,QAAQ,YAAA;AACrB,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC9C,QAAI,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,EAAG,QAAO;AAAA,EAChD;AACA,MAAI,KAAK,WAAW,GAAG,KAAK,MAAM,SAAS,KAAK,MAAM,CAAC,CAAC,EAAG,QAAO;AAClE,MAAI,KAAK,SAAS,GAAG,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC,EAAG,QAAO;AACtE,SAAO;AACT;AAQO,SAAS,kBACd,QACA,MACwB;AACxB,MAAI;AACJ,aAAW,QAAQ,UAAU,IAAI;AAC/B,QAAI,YAAY,MAAM,IAAI,cAAc,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEO,SAAS,YAAY,OAAkB,MAAyB;;AACrE,QAAM,SAAwD;AAAA,IAC5D,MAAM,KAAK,QAAQ;AAAA,IACnB,OAAO,KAAK,SAAS;AAAA,IACrB,QAAQ,KAAK,UAAU;AAAA,IACvB,QAAQ,KAAK,UAAU;AAAA,IACvB,QAAQ,KAAK,UAAU;AAAA,IACvB,MAAM,KAAK,QAAQ;AAAA,IACnB,QAAQ,KAAK,UAAU;AAAA,IACvB,OAAO,KAAK,SAAS;AAAA,EAAA;AAEvB,aAAW,SAAS,cAAc;AAChC,QAAI,CAAC,WAAW,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC,EAAG,QAAO;AAAA,EACvD;AACA,SACE,YAAY,MAAM,WAAU,UAAK,gBAAL,mBAAkB,YAAY,KAC1D,YAAY,MAAM,cAAa,UAAK,gBAAL,mBAAkB,eAAe,KAChE,YAAY,MAAM,aAAY,UAAK,gBAAL,mBAAkB,cAAc;AAElE;AAEA,SAAS,YAAY,MAA2B,MAA2B;AACzE,MAAI,SAAS,OAAW,QAAO;AAC/B,SAAO,SAAS,UAAa,SAAS;AACxC;AAcO,SAAS,0BACd,OACkB;AAClB,QAAM,OAAO,OAAO,KAAK,SAAS,CAAA,CAAE,EACjC,OAAO,CAAC,QAAQ,IAAI,KAAA,MAAW,EAAE,EACjC,KAAA;AACH,MAAI,KAAK,WAAW,EAAG,QAAO,CAAA;AAC9B,QAAM,+BAAe,IAAA;AACrB,aAAW,OAAO,MAAM;AACtB,UAAM,SAASA,MAAAA,oBAAoB,+BAAQ,IAAI;AAC/C,QAAI,OAAQ,UAAS,IAAI,KAAK,MAAM;AAAA,EACtC;AACA,QAAM,UAAU,CAAC,GAAG,SAAS,MAAM;AACnC,SAAO,iBAAiB;AAAA,IACtB,GAAG,QAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,KAAK,QAAQ,SAAS,IAAI,GAAG,IAAK;AAAA,IACpE,GAAG,QAAQ,IAAI,CAAC,SAAS,EAAE,MAAM,KAAK,QAAQ,SAAS,IAAI,GAAG,IAAK;AAAA,EAAA,CACpE;AACH;AAMA,SAAS,eACP,MACqD;AACrD,QAAM,SAAS,OAAO,KAAK,IAAI,EAAE;AAAA,IAC/B,CAAC,QACC,QAAQ,YAAY,KAAK,GAA2B,MAAM;AAAA,EAAA;AAE9D,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,QAAQ,OAAO,CAAC;AACtB,MAAI,UAAU,UAAU,UAAU,QAAS,QAAO;AAClD,QAAM,WAAW,KAAK,KAAK;AAC3B,QAAM,SAAS,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI,CAAC,GAAG,QAAQ;AACvE,MAAI,OAAO,WAAW,KAAK,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,GAAG,CAAC,GAAG;AACtE,WAAO;AAAA,EACT;AACA,SAAO,EAAE,OAAO,OAAA;AAClB;AAUO,SAAS,iBAAiB,OAA2C;AAC1E,QAAM,2BAAW,IAAA;AACjB,QAAM,OAAO,CAAC,GAAG,KAAK,EACnB,UACA,QAAQ,CAAC,SAA2B;AACnC,UAAM,QAAQ,eAAe,IAAI;AACjC,QAAI,CAAC,MAAO,QAAO,CAAC,IAAI;AACxB,UAAM,SAAS,MAAM,OAAO,OAAO,CAAC,UAAU;AAC5C,YAAM,MAAM,GAAG,MAAM,KAAK,KAAS,MAAM,aAAa;AACtD,UAAI,KAAK,IAAI,GAAG,EAAG,QAAO;AAC1B,WAAK,IAAI,GAAG;AACZ,aAAO;AAAA,IACT,CAAC;AACD,WAAO,OAAO,SAAS,IACnB,CAAC,EAAE,CAAC,MAAM,KAAK,GAAG,QAAQ,QAAQ,KAAK,OAAA,CAAQ,IAC/C,CAAA;AAAA,EACN,CAAC,EACA,QAAA;AAEH,QAAM,SAID,CAAA;AACL,MAAI,0BAAU,IAAA;AACd,MAAI;AACJ,aAAW,QAAQ,MAAM;AACvB,UAAM,QAAQ,eAAe,IAAI;AACjC,SAAI,+BAAO,WAAU,YAAY,CAAC,OAAO;AACvC,gCAAU,IAAA;AACV,iBAAW,+BAAO;AAAA,IACpB;AACA,QAAI,CAAC,OAAO;AACV,aAAO,KAAK,EAAE,QAAQ,CAAA,GAAI,MAAM;AAChC;AAAA,IACF;AACA,UAAM,SAAS,IAAI,IAAI,KAAK,MAAM;AAClC,QAAI,QAAQ;AACV,aAAO,OAAO,KAAK,GAAG,MAAM,MAAM;AAClC;AAAA,IACF;AACA,UAAM,QAAQ,EAAE,OAAO,MAAM,OAAO,QAAQ,CAAC,GAAG,MAAM,MAAM,GAAG,KAAA;AAC/D,QAAI,IAAI,KAAK,QAAQ,KAAK;AAC1B,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,OAAO;AAAA,IAAI,CAAC,EAAE,OAAO,QAAQ,KAAA,MAClC,QACI;AAAA,MACE,CAAC,KAAK,GAAG,OAAO,WAAW,IAAI,OAAO,CAAC,IAAI;AAAA,MAC3C,QAAQ,KAAK;AAAA,IAAA,IAEf;AAAA,EAAA;AAER;AAIO,SAAS,iBACd,SACA,OACkB;AAClB,SAAO,CAAC,GAAI,WAAW,CAAA,GAAK,GAAI,SAAS,CAAA,CAAG;AAC9C;AAMO,SAAS,yBAAyB,OAAkC;AACzE,MAAI,CAAC,MAAM,QAAQ,KAAK,UAAU,CAAA;AAClC,QAAM,QAA0B,CAAA;AAChC,aAAW,OAAO,OAAO;AACvB,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG;AAC3D,UAAM,OAAO;AACb,UAAM,SAASA,MAAAA,oBAAoB,KAAK,MAAM;AAC9C,QAAI,CAAC,OAAQ;AACb,UAAM,QAAmB,CAAA;AACzB,eAAW,SAAS,cAAc;AAChC,YAAM,WAAW,kBAAkB,KAAK,KAAK,CAAkB;AAC/D,UAAI,SAAS,SAAS,EAAG,OAAM,KAAK,IAAI;AAAA,IAC1C;AACA,eAAW,QAAQ,CAAC,YAAY,eAAe,YAAY,GAAY;AACrE,UAAI,OAAO,KAAK,IAAI,MAAM,UAAW,OAAM,IAAI,IAAI,KAAK,IAAI;AAAA,IAC9D;AACA,QAAI,OAAO,KAAK,KAAK,EAAE,WAAW,EAAG;AACrC,UAAM,KAAK,EAAE,GAAG,OAAO,QAAQ;AAAA,EACjC;AACA,SAAO;AACT;;;;;;;;"}
@@ -70,6 +70,15 @@ export declare function matchesTool(match: ToolMatch, tool: ToolMeta): boolean;
70
70
  * Keys are sorted so the request body is stable: an unstable order would make
71
71
  * every render look like a changed request. */
72
72
  export declare function toolPolicyFromPreferences(prefs: Record<string, ToolPolicy> | undefined): PermissionPolicy;
73
+ /** Folds exact-name and exact-group rules that share an action into one
74
+ * in-clause, so a list of per-tool toggles reads as a few strategies.
75
+ *
76
+ * Evaluation is last-match-wins, so this keeps behaviour identical: an exact
77
+ * value's earlier occurrences are dropped (the later one already wins), and
78
+ * values merge only within a contiguous run of exact rules on the same facet,
79
+ * which are disjoint by construction. Any other rule ends the run, because
80
+ * moving a value past it could change which rule matches last. */
81
+ export declare function consolidateRules(rules: PermissionPolicy): PermissionPolicy;
73
82
  /** Appends `later` onto `earlier`, the later winning. Composition rather than
74
83
  * mutation, so one caller's user rules cannot leak into another's. */
75
84
  export declare function appendToolPolicy(earlier: PermissionPolicy | undefined, later: PermissionPolicy | undefined): PermissionPolicy;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-policy.d.ts","sourceRoot":"","sources":["../../../src/data/chat/tool-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGpD;;;;;;;;;;;;;oCAaoC;AAEpC;4DAC4D;AAC5D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAE9C;;gCAEgC;AAChC,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;2CAIuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAEhE,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,cAAc,EAAE,CAAC;AAahD;;;;8DAI8D;AAC9D,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GAAG,SAAS,GAClC,OAAO,CAiBT;AAoCD;;;;;uCAKuC;AACvC,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,GAAG,SAAS,EACpC,IAAI,EAAE,QAAQ,GACb,UAAU,GAAG,SAAS,CAMxB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAmBrE;AAOD;;;;;;;;;;;gDAWgD;AAChD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAS,GAC5C,gBAAgB,CAelB;AAED;uEACuE;AACvE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,gBAAgB,GAAG,SAAS,GAClC,gBAAgB,CAElB;AAED;;;uBAGuB;AACvB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAoBzE"}
1
+ {"version":3,"file":"tool-policy.d.ts","sourceRoot":"","sources":["../../../src/data/chat/tool-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGpD;;;;;;;;;;;;;oCAaoC;AAEpC;4DAC4D;AAC5D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAE9C;;gCAEgC;AAChC,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;2CAIuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAEhE,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,cAAc,EAAE,CAAC;AAahD;;;;8DAI8D;AAC9D,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GAAG,SAAS,GAClC,OAAO,CAiBT;AAoCD;;;;;uCAKuC;AACvC,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,GAAG,SAAS,EACpC,IAAI,EAAE,QAAQ,GACb,UAAU,GAAG,SAAS,CAMxB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAmBrE;AAOD;;;;;;;;;;;gDAWgD;AAChD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAS,GAC5C,gBAAgB,CAelB;AAwBD;;;;;;;mEAOmE;AACnE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAqD1E;AAED;uEACuE;AACvE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,gBAAgB,GAAG,SAAS,GAClC,gBAAgB,CAElB;AAED;;;uBAGuB;AACvB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAoBzE"}