@speakeasy-api/moonshine 2.0.0-alpha.1 → 2.0.0-alpha.3

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 (330) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -23
  3. package/package.json +33 -50
  4. package/scripts/generate-utility-docs.js +324 -0
  5. package/src/assets/icons/external/github.svg +3 -0
  6. package/src/assets/icons/external/maven.svg +152 -0
  7. package/src/assets/icons/external/npm.svg +4 -0
  8. package/src/assets/icons/external/nuget.svg +5 -0
  9. package/src/assets/icons/external/packagist.svg +1 -0
  10. package/src/assets/icons/external/pypi.svg +182 -0
  11. package/src/assets/icons/external/rubygems.svg +14 -0
  12. package/src/assets/icons/external/terraform.svg +1 -0
  13. package/src/assets/icons/languages/csharp.svg +1 -0
  14. package/src/assets/icons/languages/go.svg +1 -0
  15. package/src/assets/icons/languages/java.svg +1 -0
  16. package/src/assets/icons/languages/json.svg +2 -0
  17. package/src/assets/icons/languages/php.svg +1 -0
  18. package/src/assets/icons/languages/postman.svg +3 -0
  19. package/src/assets/icons/languages/python.svg +1 -0
  20. package/src/assets/icons/languages/ruby.svg +1 -0
  21. package/src/assets/icons/languages/swift.svg +1 -0
  22. package/src/assets/icons/languages/terraform.svg +1 -0
  23. package/src/assets/icons/languages/typescript.svg +1 -0
  24. package/src/assets/icons/languages/unity.svg +1 -0
  25. package/src/base.css +12 -12
  26. package/src/components/AIChat/AIChatContainer.tsx +71 -0
  27. package/src/components/AIChat/AIChatMessage.tsx +135 -0
  28. package/src/components/AIChat/AIChatMessageComposer.tsx +175 -0
  29. package/src/components/AIChat/AIChatMessageList.tsx +34 -0
  30. package/src/components/AIChat/AIChatModelSelector.tsx +159 -0
  31. package/src/components/AIChat/componentsTypes.ts +36 -0
  32. package/src/components/AIChat/context.ts +15 -0
  33. package/src/components/AIChat/index.ts +12 -0
  34. package/src/components/AIChat/parts/AIChatMessageFilePart.tsx +129 -0
  35. package/src/components/AIChat/parts/AIChatMessageReasoningPart.tsx +23 -0
  36. package/src/components/AIChat/parts/AIChatMessageSourcePart.tsx +58 -0
  37. package/src/components/AIChat/parts/AIChatMessageTextPart.tsx +33 -0
  38. package/src/components/AIChat/parts/AIChatMessageToolInvocationPart.tsx +53 -0
  39. package/src/components/AIChat/parts/AIChatMessageToolPart.tsx +395 -0
  40. package/src/components/AIChat/parts/AIChatMessageToolResultPart.tsx +46 -0
  41. package/src/components/AIChat/toolCallApproval.ts +61 -0
  42. package/src/components/AIChat/types.ts +97 -0
  43. package/src/components/ActionBar/index.tsx +184 -0
  44. package/src/components/Alert/index.tsx +118 -0
  45. package/src/components/Alert/types.ts +12 -0
  46. package/src/components/AppLayout/context.tsx +31 -0
  47. package/src/components/AppLayout/index.tsx +550 -0
  48. package/src/components/AppLayout/provider.tsx +40 -0
  49. package/src/components/AppLayout/useAppLayoutKeys.ts +26 -0
  50. package/src/components/Badge/index.tsx +227 -0
  51. package/src/components/Button/index.tsx +531 -0
  52. package/src/components/Card/index.tsx +193 -0
  53. package/src/components/CodeEditorLayout/index.tsx +394 -0
  54. package/src/components/CodeEditorLayout/styles.module.css +8 -0
  55. package/src/components/CodeHighlight/Pre.tsx +63 -0
  56. package/src/components/CodePlayground/index.tsx +411 -0
  57. package/src/components/CodeSnippet/codeSnippet.css +97 -0
  58. package/src/components/CodeSnippet/index.tsx +224 -0
  59. package/src/components/Combobox/index.tsx +193 -0
  60. package/src/components/Command/index.tsx +152 -0
  61. package/src/components/Container/index.tsx +31 -0
  62. package/src/components/ContextDropdown/index.tsx +150 -0
  63. package/src/components/Dialog/index.tsx +123 -0
  64. package/src/components/DragNDrop/DragNDropArea.tsx +30 -0
  65. package/src/components/DragNDrop/DragOverlay.tsx +4 -0
  66. package/src/components/DragNDrop/Draggable.tsx +97 -0
  67. package/src/components/DragNDrop/Droppable.tsx +51 -0
  68. package/src/components/Dropdown/index.tsx +201 -0
  69. package/src/components/ExternalPill/index.tsx +58 -0
  70. package/src/components/Facepile/index.tsx +309 -0
  71. package/src/components/GradientCircle/gradientCircle.css +34 -0
  72. package/src/components/GradientCircle/index.tsx +143 -0
  73. package/src/components/Grid/index.tsx +150 -0
  74. package/src/components/Heading/index.tsx +54 -0
  75. package/src/components/HighlightedText/index.tsx +152 -0
  76. package/src/components/Icon/customIcons/createCustomLucideIcon.ts +25 -0
  77. package/src/components/Icon/customIcons/gems.ts +26 -0
  78. package/{dist/go-CiWl_aXI.mjs → src/components/Icon/customIcons/go.ts} +21 -19
  79. package/src/components/Icon/customIcons/index.ts +11 -0
  80. package/{dist/maven-DhmnGXoB.mjs → src/components/Icon/customIcons/maven.ts} +17 -15
  81. package/src/components/Icon/customIcons/npm.ts +19 -0
  82. package/{dist/nuget-5a2icRS2.mjs → src/components/Icon/customIcons/nuget.ts} +17 -15
  83. package/src/components/Icon/customIcons/packagist.ts +124 -0
  84. package/{dist/pypi-DsuRYjdK.mjs → src/components/Icon/customIcons/pypi.ts} +16 -14
  85. package/src/components/Icon/index.tsx +83 -0
  86. package/src/components/Icon/isIconName.ts +10 -0
  87. package/src/components/Icon/names.ts +14 -0
  88. package/src/components/IconButton/index.tsx +51 -0
  89. package/src/components/Input/index.tsx +98 -0
  90. package/src/components/KeyHint/index.tsx +118 -0
  91. package/src/components/LanguageIndicator/index.tsx +68 -0
  92. package/src/components/Link/index.tsx +153 -0
  93. package/src/components/LoggedInUserMenu/index.tsx +116 -0
  94. package/src/components/Logo/Animated.tsx +191 -0
  95. package/src/components/Logo/index.tsx +17 -0
  96. package/src/components/Logo/speakeasy-logo.riv +0 -0
  97. package/src/components/Logo/svgs/index.tsx +126 -0
  98. package/src/components/Modal/index.tsx +104 -0
  99. package/src/components/PageHeader/index.tsx +227 -0
  100. package/src/components/PageHeader/styles.module.css +27 -0
  101. package/src/components/Popover/index.tsx +35 -0
  102. package/src/components/PromptInput/index.tsx +372 -0
  103. package/src/components/PullRequestLink/index.tsx +64 -0
  104. package/src/components/ResizablePanel/index.tsx +119 -0
  105. package/src/components/Score/index.module.css +32 -0
  106. package/src/components/Score/index.tsx +268 -0
  107. package/src/components/ScrollArea/index.tsx +48 -0
  108. package/src/components/SegmentedButton/index.module.css +19 -0
  109. package/src/components/SegmentedButton/index.tsx +101 -0
  110. package/src/components/Select/index.tsx +159 -0
  111. package/src/components/Separator/index.tsx +23 -0
  112. package/src/components/Skeleton/index.tsx +61 -0
  113. package/src/components/Skeleton/skeleton.css +52 -0
  114. package/src/components/Stack/index.tsx +137 -0
  115. package/src/components/Subnav/index.tsx +315 -0
  116. package/src/components/Switch/index.tsx +29 -0
  117. package/src/components/Table/context/context.tsx +19 -0
  118. package/src/components/Table/context/tableProvider.tsx +39 -0
  119. package/src/components/Table/index.tsx +707 -0
  120. package/src/components/Table/styles.module.css +25 -0
  121. package/src/components/Tabs/index.tsx +87 -0
  122. package/src/components/TargetLanguageIcon/index.tsx +84 -0
  123. package/src/components/Text/index.tsx +59 -0
  124. package/src/components/ThemeSwitcher/index.tsx +118 -0
  125. package/src/components/Timeline/index.tsx +290 -0
  126. package/src/components/Tooltip/index.tsx +41 -0
  127. package/src/components/UserAvatar/index.tsx +87 -0
  128. package/src/components/UserAvatar/sizeMap.ts +12 -0
  129. package/src/components/Wizard/index.tsx +208 -0
  130. package/src/components/Wizard/types.ts +17 -0
  131. package/src/components/WorkspaceSelector/CreateOrg.tsx +95 -0
  132. package/src/components/WorkspaceSelector/CreateWorkspace.tsx +196 -0
  133. package/src/components/WorkspaceSelector/OrgList.tsx +115 -0
  134. package/src/components/WorkspaceSelector/OrgSelector.tsx +207 -0
  135. package/src/components/WorkspaceSelector/RecentWorkspaces.tsx +83 -0
  136. package/src/components/WorkspaceSelector/ScrollingList.tsx +84 -0
  137. package/src/components/WorkspaceSelector/SearchBox.tsx +40 -0
  138. package/src/components/WorkspaceSelector/WorkspaceItem.tsx +37 -0
  139. package/src/components/WorkspaceSelector/WorkspaceList.tsx +107 -0
  140. package/src/components/WorkspaceSelector/index.tsx +400 -0
  141. package/src/components/WorkspaceSelector/styles.css +74 -0
  142. package/src/components/__beta__/CLIWizard/index.tsx +357 -0
  143. package/src/components/__beta__/CLIWizard/terminal-command.tsx +108 -0
  144. package/src/components/__beta__/CLIWizard/terminal.tsx +83 -0
  145. package/src/components/__beta__/README.md +3 -0
  146. package/src/components/index.mdx +38 -0
  147. package/src/context/ConfigContext.tsx +43 -0
  148. package/src/context/ModalContext.tsx +118 -0
  149. package/src/context/theme.ts +1 -0
  150. package/src/hooks/useAppLayout.ts +10 -0
  151. package/src/hooks/useConfig.ts +10 -0
  152. package/src/hooks/useIsMounted.ts +13 -0
  153. package/src/hooks/useModal.tsx +10 -0
  154. package/src/hooks/useTailwindBreakpoint.ts +47 -0
  155. package/src/hooks/useTheme.ts +13 -0
  156. package/src/index.ts +234 -0
  157. package/src/lib/assert.ts +9 -0
  158. package/src/lib/codeUtils.ts +177 -0
  159. package/src/lib/debounce.ts +9 -0
  160. package/src/lib/responsiveMappers.ts +69 -0
  161. package/src/lib/responsiveUtils.ts +23 -0
  162. package/src/lib/storybookUtils.tsx +26 -0
  163. package/src/lib/typeUtils.ts +109 -0
  164. package/src/lib/utils.ts +85 -0
  165. package/src/styles/codeSyntax.css +59 -0
  166. package/src/styles/globals.css +51 -0
  167. package/src/types.ts +200 -0
  168. package/src/utilities.css +347 -6
  169. package/src/vite-env.d.ts +6 -0
  170. package/types/utilities.d.ts +43 -1
  171. package/dist/components/AIChat/AIChatContainer.d.ts +0 -25
  172. package/dist/components/AIChat/AIChatMessage.d.ts +0 -19
  173. package/dist/components/AIChat/AIChatMessageComposer.d.ts +0 -22
  174. package/dist/components/AIChat/AIChatMessageList.d.ts +0 -6
  175. package/dist/components/AIChat/AIChatModelSelector.d.ts +0 -14
  176. package/dist/components/AIChat/componentsTypes.d.ts +0 -11
  177. package/dist/components/AIChat/context.d.ts +0 -3
  178. package/dist/components/AIChat/index.d.ts +0 -12
  179. package/dist/components/AIChat/parts/AIChatMessageFilePart.d.ts +0 -7
  180. package/dist/components/AIChat/parts/AIChatMessageReasoningPart.d.ts +0 -5
  181. package/dist/components/AIChat/parts/AIChatMessageSourcePart.d.ts +0 -9
  182. package/dist/components/AIChat/parts/AIChatMessageTextPart.d.ts +0 -5
  183. package/dist/components/AIChat/parts/AIChatMessageToolInvocationPart.d.ts +0 -6
  184. package/dist/components/AIChat/parts/AIChatMessageToolPart.d.ts +0 -33
  185. package/dist/components/AIChat/parts/AIChatMessageToolResultPart.d.ts +0 -5
  186. package/dist/components/AIChat/toolCallApproval.d.ts +0 -15
  187. package/dist/components/AIChat/types.d.ts +0 -78
  188. package/dist/components/ActionBar/index.d.ts +0 -36
  189. package/dist/components/Alert/index.d.ts +0 -18
  190. package/dist/components/Alert/types.d.ts +0 -4
  191. package/dist/components/Badge/index.d.ts +0 -10
  192. package/dist/components/Button/index.d.ts +0 -11
  193. package/dist/components/Card/index.d.ts +0 -47
  194. package/dist/components/CodeEditorLayout/index.d.ts +0 -101
  195. package/dist/components/CodePlayground/index.d.ts +0 -108
  196. package/dist/components/CodePlayground/lineNumbers.d.ts +0 -2
  197. package/dist/components/CodePlayground/tokenTransitions.d.ts +0 -2
  198. package/dist/components/CodePlayground/wordWrap.d.ts +0 -2
  199. package/dist/components/CodeSnippet/index.d.ts +0 -50
  200. package/dist/components/Combobox/index.d.ts +0 -35
  201. package/dist/components/Command/index.d.ts +0 -80
  202. package/dist/components/Container/index.d.ts +0 -9
  203. package/dist/components/ContextDropdown/index.d.ts +0 -7
  204. package/dist/components/ContextDropdown/provider.d.ts +0 -22
  205. package/dist/components/ContextDropdown/useModal.d.ts +0 -11
  206. package/dist/components/Dialog/index.d.ts +0 -19
  207. package/dist/components/DragNDrop/DragNDropArea.d.ts +0 -8
  208. package/dist/components/DragNDrop/DragOverlay.d.ts +0 -1
  209. package/dist/components/DragNDrop/Draggable.d.ts +0 -29
  210. package/dist/components/DragNDrop/Droppable.d.ts +0 -28
  211. package/dist/components/Dropdown/index.d.ts +0 -27
  212. package/dist/components/ExternalPill/index.d.ts +0 -12
  213. package/dist/components/Facepile/index.d.ts +0 -16
  214. package/dist/components/GradientCircle/index.d.ts +0 -10
  215. package/dist/components/Grid/index.d.ts +0 -80
  216. package/dist/components/Heading/index.d.ts +0 -12
  217. package/dist/components/HighlightedText/index.d.ts +0 -19
  218. package/dist/components/Icon/customIcons/createCustomLucideIcon.d.ts +0 -3
  219. package/dist/components/Icon/customIcons/gems.d.ts +0 -2
  220. package/dist/components/Icon/customIcons/go.d.ts +0 -2
  221. package/dist/components/Icon/customIcons/index.d.ts +0 -10
  222. package/dist/components/Icon/customIcons/maven.d.ts +0 -2
  223. package/dist/components/Icon/customIcons/npm.d.ts +0 -2
  224. package/dist/components/Icon/customIcons/nuget.d.ts +0 -2
  225. package/dist/components/Icon/customIcons/packagist.d.ts +0 -2
  226. package/dist/components/Icon/customIcons/pypi.d.ts +0 -2
  227. package/dist/components/Icon/index.d.ts +0 -10
  228. package/dist/components/Icon/isIconName.d.ts +0 -2
  229. package/dist/components/Icon/names.d.ts +0 -6
  230. package/dist/components/Input/index.d.ts +0 -8
  231. package/dist/components/KeyHint/index.d.ts +0 -16
  232. package/dist/components/LanguageIndicator/index.d.ts +0 -7
  233. package/dist/components/Link/index.d.ts +0 -19
  234. package/dist/components/LoggedInUserMenu/index.d.ts +0 -17
  235. package/dist/components/Logo/Animated.d.ts +0 -7
  236. package/dist/components/Logo/index.d.ts +0 -7
  237. package/dist/components/Logo/svgs/index.d.ts +0 -6
  238. package/dist/components/Navbar/Slim.d.ts +0 -33
  239. package/dist/components/Navbar/index.d.ts +0 -15
  240. package/dist/components/PageHeader/index.d.ts +0 -45
  241. package/dist/components/Popover/index.d.ts +0 -8
  242. package/dist/components/PromptInput/index.d.ts +0 -55
  243. package/dist/components/PullRequestLink/index.d.ts +0 -10
  244. package/dist/components/ResizablePanel/index.d.ts +0 -26
  245. package/dist/components/Score/index.d.ts +0 -37
  246. package/dist/components/ScrollArea/index.d.ts +0 -5
  247. package/dist/components/Select/index.d.ts +0 -13
  248. package/dist/components/Separator/index.d.ts +0 -6
  249. package/dist/components/Skeleton/index.d.ts +0 -27
  250. package/dist/components/Stack/index.d.ts +0 -33
  251. package/dist/components/Subnav/index.d.ts +0 -12
  252. package/dist/components/Switch/index.d.ts +0 -4
  253. package/dist/components/Table/context/context.d.ts +0 -8
  254. package/dist/components/Table/context/tableProvider.d.ts +0 -6
  255. package/dist/components/Table/index.d.ts +0 -94
  256. package/dist/components/Tabs/index.d.ts +0 -21
  257. package/dist/components/TargetLanguageIcon/index.d.ts +0 -7
  258. package/dist/components/Text/index.d.ts +0 -19
  259. package/dist/components/ThemeSwitcher/index.d.ts +0 -5
  260. package/dist/components/Tooltip/index.d.ts +0 -8
  261. package/dist/components/UserAvatar/index.d.ts +0 -9
  262. package/dist/components/UserAvatar/sizeMap.d.ts +0 -3
  263. package/dist/components/Wizard/index.d.ts +0 -19
  264. package/dist/components/Wizard/types.d.ts +0 -15
  265. package/dist/components/WorkspaceSelector/CreateOrg.d.ts +0 -6
  266. package/dist/components/WorkspaceSelector/CreateWorkspace.d.ts +0 -17
  267. package/dist/components/WorkspaceSelector/OrgList.d.ts +0 -11
  268. package/dist/components/WorkspaceSelector/OrgSelector.d.ts +0 -13
  269. package/dist/components/WorkspaceSelector/RecentWorkspaces.d.ts +0 -11
  270. package/dist/components/WorkspaceSelector/ScrollingList.d.ts +0 -21
  271. package/dist/components/WorkspaceSelector/SearchBox.d.ts +0 -9
  272. package/dist/components/WorkspaceSelector/WorkspaceItem.d.ts +0 -9
  273. package/dist/components/WorkspaceSelector/WorkspaceList.d.ts +0 -10
  274. package/dist/components/WorkspaceSelector/index.d.ts +0 -34
  275. package/dist/components/__beta__/CLIWizard/index.d.ts +0 -21
  276. package/dist/components/__beta__/CLIWizard/terminal-command.d.ts +0 -19
  277. package/dist/components/__beta__/CLIWizard/terminal.d.ts +0 -26
  278. package/dist/context/ConfigContext.d.ts +0 -18
  279. package/dist/context/theme.d.ts +0 -1
  280. package/dist/createCustomLucideIcon-YlrRX5h9.mjs +0 -19
  281. package/dist/createCustomLucideIcon-YlrRX5h9.mjs.map +0 -1
  282. package/dist/gems-BcsO9cXq.mjs +0 -24
  283. package/dist/gems-BcsO9cXq.mjs.map +0 -1
  284. package/dist/github-kgjMtfE7.mjs +0 -11
  285. package/dist/github-kgjMtfE7.mjs.map +0 -1
  286. package/dist/go-CiWl_aXI.mjs.map +0 -1
  287. package/dist/hooks/useConfig.d.ts +0 -2
  288. package/dist/hooks/useIsMounted.d.ts +0 -1
  289. package/dist/hooks/useTailwindBreakpoint.d.ts +0 -3
  290. package/dist/hooks/useTheme.d.ts +0 -6
  291. package/dist/index-COXZ9O-g.mjs +0 -50882
  292. package/dist/index-COXZ9O-g.mjs.map +0 -1
  293. package/dist/index.d.ts +0 -73
  294. package/dist/lib/assert.d.ts +0 -2
  295. package/dist/lib/codeUtils.d.ts +0 -35
  296. package/dist/lib/debounce.d.ts +0 -1
  297. package/dist/lib/responsiveMappers.d.ts +0 -10
  298. package/dist/lib/responsiveUtils.d.ts +0 -3
  299. package/dist/lib/storybookUtils.d.ts +0 -5
  300. package/dist/lib/typeUtils.d.ts +0 -24
  301. package/dist/lib/utils.d.ts +0 -23
  302. package/dist/lucide-icons-BDw0imyx.mjs +0 -28054
  303. package/dist/lucide-icons-BDw0imyx.mjs.map +0 -1
  304. package/dist/maven-DhmnGXoB.mjs.map +0 -1
  305. package/dist/maven-W_nkSDNW.mjs +0 -107
  306. package/dist/maven-W_nkSDNW.mjs.map +0 -1
  307. package/dist/moonshine.es.js +0 -114
  308. package/dist/moonshine.es.js.map +0 -1
  309. package/dist/npm-BWTcVvFH.mjs +0 -11
  310. package/dist/npm-BWTcVvFH.mjs.map +0 -1
  311. package/dist/npm-CvQ4GKW4.mjs +0 -17
  312. package/dist/npm-CvQ4GKW4.mjs.map +0 -1
  313. package/dist/nuget-5a2icRS2.mjs.map +0 -1
  314. package/dist/nuget-CV5HU1JR.mjs +0 -11
  315. package/dist/nuget-CV5HU1JR.mjs.map +0 -1
  316. package/dist/packagist-CET6q9hi.mjs +0 -118
  317. package/dist/packagist-CET6q9hi.mjs.map +0 -1
  318. package/dist/packagist-D01fn9N_.mjs +0 -11
  319. package/dist/packagist-D01fn9N_.mjs.map +0 -1
  320. package/dist/pypi-DLh6kIJe.mjs +0 -11
  321. package/dist/pypi-DLh6kIJe.mjs.map +0 -1
  322. package/dist/pypi-DsuRYjdK.mjs.map +0 -1
  323. package/dist/rubygems-DeiNjcDV.mjs +0 -11
  324. package/dist/rubygems-DeiNjcDV.mjs.map +0 -1
  325. package/dist/speakeasy-logo-ByBTXLWb.mjs +0 -5
  326. package/dist/speakeasy-logo-ByBTXLWb.mjs.map +0 -1
  327. package/dist/style.css +0 -1
  328. package/dist/terraform-C4aktQ0o.mjs +0 -11
  329. package/dist/terraform-C4aktQ0o.mjs.map +0 -1
  330. package/dist/types.d.ts +0 -80
@@ -0,0 +1,53 @@
1
+ import { cn } from '../../../lib/utils'
2
+ import { Text } from '../../Text'
3
+ import type { BasePartProps } from '../types'
4
+
5
+ export interface AIChatMessageToolInvocationPartProps extends BasePartProps {
6
+ toolName: string
7
+ toolInput?: Record<string, unknown>
8
+ }
9
+
10
+ export function AIChatMessageToolInvocationPart({
11
+ toolName,
12
+ toolInput,
13
+ className,
14
+ }: AIChatMessageToolInvocationPartProps) {
15
+ return (
16
+ <div
17
+ className={cn(
18
+ 'rounded-md border border-neutral-600 bg-neutral-800 p-3',
19
+ className
20
+ )}
21
+ >
22
+ <div className="mb-1 flex items-center gap-2">
23
+ <svg
24
+ xmlns="http://www.w3.org/2000/svg"
25
+ className="h-4 w-4 text-neutral-400"
26
+ fill="none"
27
+ viewBox="0 0 24 24"
28
+ stroke="currentColor"
29
+ >
30
+ <path
31
+ strokeLinecap="round"
32
+ strokeLinejoin="round"
33
+ strokeWidth={2}
34
+ d="M13 10V3L4 14h7v7l9-11h-7z"
35
+ />
36
+ </svg>
37
+ <Text variant="xs" className="font-medium text-neutral-50">
38
+ Tool Invocation: {toolName}
39
+ </Text>
40
+ </div>
41
+ {toolInput && (
42
+ <div className="mt-2">
43
+ <Text variant="xs" className="mb-1 font-medium text-neutral-200">
44
+ Input:
45
+ </Text>
46
+ <pre className="typography-body-xs rounded bg-neutral-900 p-2 whitespace-pre-wrap text-neutral-300">
47
+ {JSON.stringify(toolInput, null, 2)}
48
+ </pre>
49
+ </div>
50
+ )}
51
+ </div>
52
+ )
53
+ }
@@ -0,0 +1,395 @@
1
+ import { motion, MotionConfig } from 'motion/react'
2
+ import { CheckIcon, UserCheck, XIcon } from 'lucide-react'
3
+ import { useEffect, useMemo, useState } from 'react'
4
+ import { cn } from '../../../lib/utils'
5
+ import { Button } from '../../Button'
6
+ import { IconButton } from '../../IconButton'
7
+ import { Text } from '../../Text'
8
+ import {
9
+ BaseComponents,
10
+ DefaultComponents,
11
+ FcOrClassName,
12
+ renderComponent,
13
+ } from '../componentsTypes'
14
+ import { useAIChat } from '../context'
15
+ import {
16
+ TOOL_CALL_ERROR_MESSAGE,
17
+ TOOL_CALL_REJECTED_MESSAGE,
18
+ } from '../toolCallApproval'
19
+ import type { BasePartProps } from '../types'
20
+
21
+ type ToolInvocationState = 'partial-call' | 'call' | 'result'
22
+
23
+ type ToolInvocationStatus = 'pending' | 'in-progress' | 'success' | 'error'
24
+
25
+ interface ToolInvocation {
26
+ state: ToolInvocationState
27
+ toolCallId: string
28
+ toolName: string
29
+ args: Record<string, unknown>
30
+ result?: unknown
31
+ }
32
+
33
+ export interface AIChatMessageToolPartProps extends BasePartProps {
34
+ toolInvocation: ToolInvocation
35
+ components?: Partial<AIChatMessageToolPartComponents>
36
+ onAccept?: () => void
37
+ onReject?: () => void
38
+ }
39
+
40
+ export interface AIChatMessageToolPartComponents extends BaseComponents {
41
+ toolName: FcOrClassName<ToolInvocation & { confirmMessage?: string }>
42
+ statusIndicator: FcOrClassName<{ status: ToolInvocationStatus }>
43
+ input: FcOrClassName<Omit<ToolInvocation, 'args'> & { args: string }>
44
+ result: FcOrClassName<Omit<ToolInvocation, 'result'> & { result: string }>
45
+ }
46
+
47
+ const inputResultClassName =
48
+ 'typography-body-xs max-h-48 overflow-auto rounded p-2 break-all whitespace-pre-wrap text-foreground bg-muted'
49
+
50
+ const defaultComponents: DefaultComponents<AIChatMessageToolPartComponents> = {
51
+ toolName: ({ toolName, confirmMessage, className }) => (
52
+ <Text
53
+ variant="xs"
54
+ className={cn('text-foreground flex-1 py-1 font-medium', className)}
55
+ >
56
+ {confirmMessage || toolName}
57
+ </Text>
58
+ ),
59
+ statusIndicator: ({ status, className }) => (
60
+ <StatusIndicator status={status} className={className} />
61
+ ),
62
+ input: ({ args, className }) => (
63
+ <>
64
+ <Text variant="xs" className="text-foreground mb-1 font-medium">
65
+ Input
66
+ </Text>
67
+ <pre className={cn(inputResultClassName, className)}>{args}</pre>
68
+ </>
69
+ ),
70
+ result: ({ result, className }) => (
71
+ <>
72
+ <Text variant="xs" className="text-foreground mb-1 font-medium">
73
+ Result
74
+ </Text>
75
+ <pre className={cn(inputResultClassName, className)}>{result}</pre>
76
+ </>
77
+ ),
78
+ }
79
+
80
+ export function AIChatMessageToolPart({
81
+ toolInvocation,
82
+ className,
83
+ components,
84
+ }: AIChatMessageToolPartProps) {
85
+ const { state, toolCallId, args, result } = toolInvocation
86
+ const [isExpanded, setIsExpanded] = useState(false)
87
+
88
+ const { toolCallApproval } = useAIChat()
89
+ const isPending = toolCallId === toolCallApproval?.pendingToolCall?.toolCallId
90
+
91
+ useEffect(() => {
92
+ if (isPending) {
93
+ setIsExpanded(true)
94
+ }
95
+ }, [isPending])
96
+
97
+ useEffect(() => {
98
+ if (state === 'result') {
99
+ setIsExpanded(false)
100
+ } else {
101
+ setIsExpanded(true)
102
+ }
103
+ }, [state])
104
+
105
+ // Format the result for display
106
+ const formatResult = (result: unknown): string => {
107
+ if (typeof result === 'string') return result
108
+ if (typeof result === 'object' && result !== null)
109
+ return JSON.stringify(result as Record<string, unknown>, null, 2)
110
+ return String(result)
111
+ }
112
+
113
+ const status = useMemo(() => {
114
+ if (isPending) return 'pending'
115
+ if (state === 'call') return 'in-progress'
116
+ if (state === 'result') {
117
+ if (formatResult(result).includes(TOOL_CALL_ERROR_MESSAGE)) return 'error'
118
+ if (formatResult(result).includes(TOOL_CALL_REJECTED_MESSAGE))
119
+ return 'error'
120
+ return 'success'
121
+ }
122
+ return 'pending'
123
+ }, [state, isPending, result])
124
+
125
+ return (
126
+ <MotionConfig transition={{ duration: 0.2 }}>
127
+ <motion.div
128
+ className={cn(
129
+ 'overflow-hidden rounded-lg border transition-all duration-300',
130
+ className
131
+ )}
132
+ initial={false}
133
+ animate={isExpanded ? 'expanded' : 'collapsed'}
134
+ >
135
+ {/* Header */}
136
+ <div
137
+ className={cn('bg-muted flex items-center gap-3 px-4 py-2', {
138
+ 'border-b': isExpanded,
139
+ })}
140
+ >
141
+ {/* Status Indicator */}
142
+ <div className="relative flex h-6 w-6 items-center justify-center">
143
+ {renderComponent(defaultComponents, components, 'statusIndicator', {
144
+ status,
145
+ })}
146
+ </div>
147
+ {/* Tool Name */}
148
+ {renderComponent(defaultComponents, components, 'toolName', {
149
+ ...toolInvocation,
150
+ confirmMessage: toolCallApproval?.pendingToolCall?.confirmMessage,
151
+ })}
152
+
153
+ {/* Action Buttons */}
154
+ <div className="flex items-center gap-1">
155
+ <IconButton
156
+ variant="tertiary"
157
+ onClick={() => setIsExpanded(!isExpanded)}
158
+ className="h-6 w-6"
159
+ aria-label={isExpanded ? 'Collapse' : 'Expand'}
160
+ icon={
161
+ <motion.svg
162
+ xmlns="http://www.w3.org/2000/svg"
163
+ className="h-4 w-4"
164
+ fill="none"
165
+ viewBox="0 0 24 24"
166
+ stroke="currentColor"
167
+ variants={{
168
+ expanded: { rotate: 180 },
169
+ collapsed: { rotate: 0 },
170
+ }}
171
+ animate={isExpanded ? 'expanded' : 'collapsed'}
172
+ transition={{ duration: 0.2, ease: 'easeInOut' }}
173
+ >
174
+ <path
175
+ strokeLinecap="round"
176
+ strokeLinejoin="round"
177
+ strokeWidth={2}
178
+ d="M19 9l-7 7-7-7"
179
+ />
180
+ </motion.svg>
181
+ }
182
+ />
183
+ </div>
184
+ </div>
185
+
186
+ {/* Expandable Body */}
187
+ <motion.div
188
+ variants={{
189
+ expanded: {
190
+ height: 'auto',
191
+ opacity: 1,
192
+ maskImage:
193
+ 'linear-gradient(to bottom, black 100%, transparent 100%)',
194
+ transition: {
195
+ height: { duration: 0.3 },
196
+ opacity: { duration: 0.2, delay: 0.1 },
197
+ maskImage: { duration: 0.3 },
198
+ },
199
+ },
200
+ collapsed: {
201
+ height: 0,
202
+ opacity: 0,
203
+ maskImage:
204
+ 'linear-gradient(to bottom, black 50%, transparent 100%)',
205
+ transition: {
206
+ height: { duration: 0.3 },
207
+ opacity: { duration: 0.1 },
208
+ maskImage: { duration: 0.3 },
209
+ },
210
+ },
211
+ }}
212
+ className="overflow-hidden"
213
+ >
214
+ <motion.div
215
+ variants={{
216
+ expanded: {
217
+ filter: 'blur(0px)',
218
+ opacity: 1,
219
+ },
220
+ collapsed: {
221
+ filter: 'blur(2px)',
222
+ opacity: 0,
223
+ },
224
+ }}
225
+ className="space-y-3 p-4"
226
+ >
227
+ {/* Tool Input */}
228
+ {args && Object.keys(args).length > 0 ? (
229
+ <motion.div
230
+ variants={{
231
+ expanded: { y: 0, opacity: 1 },
232
+ collapsed: { y: -10, opacity: 0 },
233
+ }}
234
+ >
235
+ {renderComponent(defaultComponents, components, 'input', {
236
+ ...toolInvocation,
237
+ args: JSON.stringify(
238
+ args as Record<string, unknown>,
239
+ null,
240
+ 2
241
+ ),
242
+ })}
243
+ </motion.div>
244
+ ) : null}
245
+
246
+ {/* Tool Result */}
247
+ {state === 'result' && result ? (
248
+ <motion.div
249
+ variants={{
250
+ expanded: { y: 0, opacity: 1 },
251
+ collapsed: { y: -10, opacity: 0 },
252
+ }}
253
+ >
254
+ {renderComponent(defaultComponents, components, 'result', {
255
+ ...toolInvocation,
256
+ result: formatResult(result),
257
+ })}
258
+ </motion.div>
259
+ ) : null}
260
+ </motion.div>
261
+ </motion.div>
262
+
263
+ {/* Approve / Reject Footer */}
264
+ {isPending && (
265
+ <div className="bg-muted flex justify-end border-t px-4 py-2">
266
+ <div className="flex items-center gap-1.5">
267
+ <Button
268
+ variant="tertiary"
269
+ size="sm"
270
+ onClick={toolCallApproval?.pendingToolCall?.reject}
271
+ className="hover:bg-background hover:text-foreground h-7 border border-transparent px-3 text-sm"
272
+ >
273
+ Reject
274
+ </Button>
275
+
276
+ <Button
277
+ size="sm"
278
+ onClick={toolCallApproval?.pendingToolCall?.approve}
279
+ className="bg-foreground text-background h-7 border border-transparent px-3 text-sm"
280
+ >
281
+ Accept
282
+ </Button>
283
+ </div>
284
+ </div>
285
+ )}
286
+ </motion.div>
287
+ </MotionConfig>
288
+ )
289
+ }
290
+
291
+ const StatusIndicator = ({
292
+ status,
293
+ className,
294
+ }: {
295
+ status: ToolInvocationStatus
296
+ className: string
297
+ }) => {
298
+ const widthHeight = 'h-3 w-3'
299
+ const baseClassName = `${widthHeight} flex items-center justify-center rounded-full`
300
+
301
+ switch (status) {
302
+ case 'success':
303
+ return (
304
+ <motion.div
305
+ className={cn(baseClassName, 'bg-success', className)}
306
+ initial={{ scale: 0.8 }}
307
+ animate={{ scale: 1 }}
308
+ transition={{ type: 'spring', stiffness: 500, damping: 15 }}
309
+ >
310
+ <CheckIcon className="h-full w-full" />
311
+ </motion.div>
312
+ )
313
+ case 'error':
314
+ return (
315
+ <motion.div
316
+ className={cn(baseClassName, 'bg-destructive', className)}
317
+ initial={{ scale: 0.8 }}
318
+ animate={{ scale: 1 }}
319
+ transition={{ type: 'spring', stiffness: 500, damping: 15 }}
320
+ >
321
+ <XIcon className="h-full w-full" />
322
+ </motion.div>
323
+ )
324
+ case 'pending':
325
+ return (
326
+ <>
327
+ {/* Track */}
328
+ <motion.div
329
+ className="absolute inset-0 rounded-full"
330
+ initial={{ opacity: 0 }}
331
+ animate={{ opacity: 1 }}
332
+ transition={{ duration: 0.2 }}
333
+ />
334
+ {/* Animated Ring */}
335
+ <motion.div
336
+ className="absolute inset-0"
337
+ initial={{ opacity: 0 }}
338
+ animate={{ opacity: 1 }}
339
+ transition={{ duration: 0.2 }}
340
+ >
341
+ <div
342
+ className="h-full w-full rounded-full border-2 [border-top-color:transparent] [border-left-color:transparent]"
343
+ style={{
344
+ animation: 'spin 3s linear infinite',
345
+ }}
346
+ />
347
+ </motion.div>
348
+ <motion.div
349
+ className={cn('relative h-4 w-4 rounded-full', className)}
350
+ initial={{ scale: 0.8 }}
351
+ animate={{ scale: 1 }}
352
+ transition={{ type: 'spring', stiffness: 500, damping: 15 }}
353
+ >
354
+ <UserCheck className="h-full w-full" />
355
+ </motion.div>
356
+ </>
357
+ )
358
+ case 'in-progress':
359
+ return (
360
+ <>
361
+ {/* Track */}
362
+ <motion.div
363
+ className="bg-information-fill/20 absolute inset-0 rounded-full"
364
+ initial={{ opacity: 0 }}
365
+ animate={{ opacity: 1 }}
366
+ transition={{ duration: 0.2 }}
367
+ />
368
+ {/* Animated Ring */}
369
+ <motion.div
370
+ className="absolute inset-0"
371
+ initial={{ opacity: 0 }}
372
+ animate={{ opacity: 1 }}
373
+ transition={{ duration: 0.2 }}
374
+ >
375
+ <div
376
+ className="border-information-fill h-full w-full rounded-full border-2 [border-top-color:transparent] [border-left-color:transparent]"
377
+ style={{
378
+ animation: 'spin 1s linear infinite',
379
+ }}
380
+ />
381
+ </motion.div>
382
+ <motion.div
383
+ className={cn(
384
+ widthHeight,
385
+ 'bg-information-fill relative rounded-full',
386
+ className
387
+ )}
388
+ initial={{ scale: 0.8 }}
389
+ animate={{ scale: 1 }}
390
+ transition={{ type: 'spring', stiffness: 500, damping: 15 }}
391
+ />
392
+ </>
393
+ )
394
+ }
395
+ }
@@ -0,0 +1,46 @@
1
+ import { cn } from '../../../lib/utils'
2
+ import { Text } from '../../Text'
3
+ import type { BasePartProps } from '../types'
4
+
5
+ export interface AIChatMessageToolResultPartProps extends BasePartProps {
6
+ content: string
7
+ }
8
+
9
+ export function AIChatMessageToolResultPart({
10
+ content,
11
+ className,
12
+ }: AIChatMessageToolResultPartProps) {
13
+ return (
14
+ <div
15
+ className={cn(
16
+ 'rounded-md border border-neutral-600 bg-neutral-800 p-3',
17
+ className
18
+ )}
19
+ >
20
+ <div className="mb-1 flex items-center gap-2">
21
+ <svg
22
+ xmlns="http://www.w3.org/2000/svg"
23
+ className="h-4 w-4 text-neutral-400"
24
+ fill="none"
25
+ viewBox="0 0 24 24"
26
+ stroke="currentColor"
27
+ >
28
+ <path
29
+ strokeLinecap="round"
30
+ strokeLinejoin="round"
31
+ strokeWidth={2}
32
+ d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
33
+ />
34
+ </svg>
35
+ <Text variant="xs" className="font-medium text-neutral-50">
36
+ Tool Result
37
+ </Text>
38
+ </div>
39
+ <div className="mt-2">
40
+ <pre className="typography-body-xs rounded bg-neutral-900 p-2 whitespace-pre-wrap text-neutral-300">
41
+ {content}
42
+ </pre>
43
+ </div>
44
+ </div>
45
+ )
46
+ }
@@ -0,0 +1,61 @@
1
+ import { ToolCall } from 'ai'
2
+ import { useState } from 'react'
3
+ import { ToolCallApprovalProps, ToolCallWithApproval } from './types'
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ type TC = ToolCall<string, any>
7
+ type ToolCallFn = (t: { toolCall: TC }) => Promise<string>
8
+
9
+ export const TOOL_CALL_ERROR_MESSAGE = 'Tool call error'
10
+ export const TOOL_CALL_REJECTED_MESSAGE = 'User rejected tool call'
11
+
12
+ export function useToolCallApproval({
13
+ executeToolCall,
14
+ requiresApproval,
15
+ }: {
16
+ executeToolCall: (toolCall: TC) => Promise<string>
17
+ requiresApproval?: (toolCall: TC) => boolean | string
18
+ }): ToolCallApprovalProps & { toolCallFn: ToolCallFn } {
19
+ const [pendingToolCall, setPendingToolCall] =
20
+ useState<ToolCallWithApproval | null>(null)
21
+
22
+ const executeWithErrorHandling = async (toolCall: TC) => {
23
+ try {
24
+ return await executeToolCall(toolCall)
25
+ } catch (error) {
26
+ return `${TOOL_CALL_ERROR_MESSAGE}: ${error}`
27
+ }
28
+ }
29
+
30
+ const toolCallFn = async ({ toolCall }: { toolCall: TC }) => {
31
+ const confirmMessage = requiresApproval?.(toolCall)
32
+ if (!confirmMessage) {
33
+ return executeWithErrorHandling(toolCall)
34
+ }
35
+
36
+ // If the tool call requires approval, return a promise that resolves when the user approves the tool call
37
+ return new Promise<string>((resolve, reject) => {
38
+ setPendingToolCall({
39
+ ...toolCall,
40
+ approve: () => resolve('approved'),
41
+ reject: () => reject('rejected'),
42
+ ...(typeof confirmMessage === 'string' && {
43
+ confirmMessage,
44
+ }),
45
+ })
46
+ })
47
+ .then(async () => {
48
+ setPendingToolCall(null)
49
+ return executeWithErrorHandling(toolCall)
50
+ })
51
+ .catch(() => {
52
+ setPendingToolCall(null)
53
+ return TOOL_CALL_REJECTED_MESSAGE
54
+ })
55
+ }
56
+
57
+ return {
58
+ pendingToolCall,
59
+ toolCallFn,
60
+ }
61
+ }
@@ -0,0 +1,97 @@
1
+ import { ToolCall } from 'ai'
2
+
3
+ export type MessageRole = 'user' | 'assistant' | 'system'
4
+
5
+ export type ToolArgs = {
6
+ target_file?: string
7
+ should_read_entire_file?: boolean
8
+ query?: string
9
+ target_directories?: string[]
10
+ instructions?: string
11
+ code_edit?: string
12
+ command?: string
13
+ is_background?: boolean
14
+ explanation?: string
15
+ }
16
+
17
+ export type ToolInvocation = {
18
+ type: 'tool-invocation'
19
+ toolInvocation: {
20
+ toolName: string
21
+ toolCallId: string
22
+ state: 'partial-call' | 'call' | 'result'
23
+ args: ToolArgs
24
+ }
25
+ }
26
+
27
+ export type ToolResult = {
28
+ type: 'tool-result'
29
+ toolCallId: string
30
+ content: string
31
+ }
32
+
33
+ export type TextPart = {
34
+ type: 'text'
35
+ text: string
36
+ }
37
+
38
+ export type ReasoningPart = {
39
+ type: 'reasoning'
40
+ reasoning: string
41
+ }
42
+
43
+ export type FilePart = {
44
+ type: 'file'
45
+ mimeType: string
46
+ data: string
47
+ fileName: string
48
+ }
49
+
50
+ export type SourcePart = {
51
+ type: 'source'
52
+ source: {
53
+ id: string
54
+ url: string
55
+ title: string
56
+ }
57
+ }
58
+
59
+ export type MessagePart =
60
+ | TextPart
61
+ | ReasoningPart
62
+ | ToolInvocation
63
+ | ToolResult
64
+ | FilePart
65
+ | SourcePart
66
+
67
+ export type ChatMessage = {
68
+ id: string
69
+ role: 'user' | 'assistant'
70
+ parts: MessagePart[]
71
+ }
72
+
73
+ export interface AIChatContextValue {
74
+ messages: ChatMessage[]
75
+ isLoading?: boolean
76
+ onSendMessage?: (message: string) => void
77
+ model?: string
78
+ onModelChange?: (model: string) => void
79
+ availableModels?: { label: string; value: string }[]
80
+ toolCallApproval?: ToolCallApprovalProps
81
+ initialInput?: string
82
+ }
83
+
84
+ export interface BasePartProps {
85
+ className?: string
86
+ }
87
+
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ export type ToolCallWithApproval = ToolCall<string, any> & {
90
+ approve: () => void
91
+ reject: () => void
92
+ confirmMessage?: string
93
+ }
94
+
95
+ export interface ToolCallApprovalProps {
96
+ pendingToolCall: ToolCallWithApproval | null
97
+ }