@assistant-ui/react-ink 0.0.1 → 0.0.4

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 (244) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -0
  3. package/dist/context/AssistantContext.d.ts +1 -7
  4. package/dist/context/AssistantContext.d.ts.map +1 -1
  5. package/dist/context/AssistantContext.js +1 -15
  6. package/dist/context/AssistantContext.js.map +1 -1
  7. package/dist/context/index.d.ts +1 -1
  8. package/dist/context/index.d.ts.map +1 -1
  9. package/dist/context/index.js +1 -1
  10. package/dist/context/index.js.map +1 -1
  11. package/dist/index.d.ts +13 -14
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +13 -16
  14. package/dist/index.js.map +1 -1
  15. package/dist/primitives/actionBar/ActionBarCopy.d.ts +1 -1
  16. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  17. package/dist/primitives/actionBar/ActionBarCopy.js +1 -1
  18. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  19. package/dist/primitives/actionBar/ActionBarEdit.js +1 -1
  20. package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
  21. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +1 -1
  22. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  23. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +1 -1
  24. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  25. package/dist/primitives/actionBar/ActionBarReload.js +1 -1
  26. package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
  27. package/dist/primitives/actionBar/index.d.ts +5 -5
  28. package/dist/primitives/actionBar/index.d.ts.map +1 -1
  29. package/dist/primitives/actionBar/index.js +5 -5
  30. package/dist/primitives/actionBar/index.js.map +1 -1
  31. package/dist/primitives/attachment/index.d.ts +4 -4
  32. package/dist/primitives/attachment/index.d.ts.map +1 -1
  33. package/dist/primitives/attachment/index.js +4 -4
  34. package/dist/primitives/attachment/index.js.map +1 -1
  35. package/dist/primitives/branchPicker/index.d.ts +4 -4
  36. package/dist/primitives/branchPicker/index.d.ts.map +1 -1
  37. package/dist/primitives/branchPicker/index.js +4 -4
  38. package/dist/primitives/branchPicker/index.js.map +1 -1
  39. package/dist/primitives/chainOfThought/index.d.ts +3 -3
  40. package/dist/primitives/chainOfThought/index.d.ts.map +1 -1
  41. package/dist/primitives/chainOfThought/index.js +3 -3
  42. package/dist/primitives/chainOfThought/index.js.map +1 -1
  43. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  44. package/dist/primitives/composer/ComposerAddAttachment.js +3 -5
  45. package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
  46. package/dist/primitives/composer/ComposerCancel.js +3 -3
  47. package/dist/primitives/composer/ComposerCancel.js.map +1 -1
  48. package/dist/primitives/composer/ComposerSend.js +3 -3
  49. package/dist/primitives/composer/ComposerSend.js.map +1 -1
  50. package/dist/primitives/composer/index.d.ts +7 -10
  51. package/dist/primitives/composer/index.d.ts.map +1 -1
  52. package/dist/primitives/composer/index.js +7 -10
  53. package/dist/primitives/composer/index.js.map +1 -1
  54. package/dist/primitives/message/MessageContent.d.ts.map +1 -1
  55. package/dist/primitives/message/MessageContent.js +9 -3
  56. package/dist/primitives/message/MessageContent.js.map +1 -1
  57. package/dist/primitives/message/index.d.ts +5 -5
  58. package/dist/primitives/message/index.d.ts.map +1 -1
  59. package/dist/primitives/message/index.js +5 -5
  60. package/dist/primitives/message/index.js.map +1 -1
  61. package/dist/primitives/suggestion/index.d.ts +3 -3
  62. package/dist/primitives/suggestion/index.d.ts.map +1 -1
  63. package/dist/primitives/suggestion/index.js +3 -3
  64. package/dist/primitives/suggestion/index.js.map +1 -1
  65. package/dist/primitives/thread/ThreadEmpty.js +1 -1
  66. package/dist/primitives/thread/ThreadEmpty.js.map +1 -1
  67. package/dist/primitives/thread/ThreadMessages.d.ts +23 -7
  68. package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
  69. package/dist/primitives/thread/ThreadMessages.js +67 -13
  70. package/dist/primitives/thread/ThreadMessages.js.map +1 -1
  71. package/dist/primitives/thread/index.d.ts +7 -7
  72. package/dist/primitives/thread/index.d.ts.map +1 -1
  73. package/dist/primitives/thread/index.js +7 -7
  74. package/dist/primitives/thread/index.js.map +1 -1
  75. package/dist/primitives/threadList/index.d.ts +3 -3
  76. package/dist/primitives/threadList/index.d.ts.map +1 -1
  77. package/dist/primitives/threadList/index.js +3 -3
  78. package/dist/primitives/threadList/index.js.map +1 -1
  79. package/dist/primitives/threadListItem/index.d.ts +6 -6
  80. package/dist/primitives/threadListItem/index.d.ts.map +1 -1
  81. package/dist/primitives/threadListItem/index.js +6 -6
  82. package/dist/primitives/threadListItem/index.js.map +1 -1
  83. package/dist/primitives/toolCall/ToolFallback.d.ts +33 -0
  84. package/dist/primitives/toolCall/ToolFallback.d.ts.map +1 -0
  85. package/dist/primitives/toolCall/ToolFallback.js +103 -0
  86. package/dist/primitives/toolCall/ToolFallback.js.map +1 -0
  87. package/dist/primitives/toolCall/index.d.ts +2 -0
  88. package/dist/primitives/toolCall/index.d.ts.map +1 -0
  89. package/dist/primitives/toolCall/index.js +2 -0
  90. package/dist/primitives/toolCall/index.js.map +1 -0
  91. package/dist/runtimes/RemoteThreadListHookInstanceManager.d.ts +1 -95
  92. package/dist/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  93. package/dist/runtimes/RemoteThreadListHookInstanceManager.js +1 -109
  94. package/dist/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  95. package/dist/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +1 -112
  96. package/dist/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  97. package/dist/runtimes/RemoteThreadListThreadListRuntimeCore.js +1 -439
  98. package/dist/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  99. package/dist/runtimes/useLocalRuntime.d.ts +1 -17
  100. package/dist/runtimes/useLocalRuntime.d.ts.map +1 -1
  101. package/dist/runtimes/useLocalRuntime.js +1 -61
  102. package/dist/runtimes/useLocalRuntime.js.map +1 -1
  103. package/dist/runtimes/useRemoteThreadListRuntime.d.ts +1 -3
  104. package/dist/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  105. package/dist/runtimes/useRemoteThreadListRuntime.js +1 -46
  106. package/dist/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  107. package/package.json +13 -11
  108. package/src/context/AssistantContext.tsx +4 -31
  109. package/src/context/index.ts +4 -1
  110. package/src/index.ts +13 -39
  111. package/src/primitives/actionBar/ActionBarCopy.tsx +1 -1
  112. package/src/primitives/actionBar/ActionBarEdit.tsx +1 -1
  113. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +1 -1
  114. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +1 -1
  115. package/src/primitives/actionBar/ActionBarReload.tsx +1 -1
  116. package/src/primitives/actionBar/index.ts +16 -7
  117. package/src/primitives/attachment/index.ts +14 -5
  118. package/src/primitives/branchPicker/index.ts +8 -8
  119. package/src/primitives/chainOfThought/index.ts +5 -5
  120. package/src/primitives/composer/ComposerAddAttachment.tsx +3 -5
  121. package/src/primitives/composer/ComposerCancel.tsx +3 -3
  122. package/src/primitives/composer/ComposerSend.tsx +3 -3
  123. package/src/primitives/composer/index.ts +19 -19
  124. package/src/primitives/message/MessageContent.test.tsx +83 -0
  125. package/src/primitives/message/MessageContent.tsx +21 -15
  126. package/src/primitives/message/index.ts +13 -7
  127. package/src/primitives/suggestion/index.ts +6 -6
  128. package/src/primitives/thread/ThreadEmpty.tsx +1 -1
  129. package/src/primitives/thread/ThreadMessages.tsx +122 -27
  130. package/src/primitives/thread/index.ts +17 -11
  131. package/src/primitives/threadList/index.ts +12 -3
  132. package/src/primitives/threadListItem/index.ts +11 -11
  133. package/src/primitives/toolCall/ToolFallback.test.tsx +40 -0
  134. package/src/primitives/toolCall/ToolFallback.tsx +227 -0
  135. package/src/primitives/toolCall/index.ts +5 -0
  136. package/src/runtimes/RemoteThreadListHookInstanceManager.tsx +1 -180
  137. package/src/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +1 -538
  138. package/src/runtimes/useLocalRuntime.ts +4 -105
  139. package/src/runtimes/useRemoteThreadListRuntime.ts +1 -80
  140. package/dist/adapters/LocalStorageThreadListAdapter.d.ts +0 -15
  141. package/dist/adapters/LocalStorageThreadListAdapter.d.ts.map +0 -1
  142. package/dist/adapters/LocalStorageThreadListAdapter.js +0 -154
  143. package/dist/adapters/LocalStorageThreadListAdapter.js.map +0 -1
  144. package/dist/adapters/TitleGenerationAdapter.d.ts +0 -6
  145. package/dist/adapters/TitleGenerationAdapter.d.ts.map +0 -1
  146. package/dist/adapters/TitleGenerationAdapter.js +0 -15
  147. package/dist/adapters/TitleGenerationAdapter.js.map +0 -1
  148. package/dist/adapters/index.d.ts +0 -3
  149. package/dist/adapters/index.d.ts.map +0 -1
  150. package/dist/adapters/index.js +0 -3
  151. package/dist/adapters/index.js.map +0 -1
  152. package/dist/primitive-hooks/index.d.ts +0 -15
  153. package/dist/primitive-hooks/index.d.ts.map +0 -1
  154. package/dist/primitive-hooks/index.js +0 -15
  155. package/dist/primitive-hooks/index.js.map +0 -1
  156. package/dist/primitive-hooks/useActionBarCopy.d.ts +0 -10
  157. package/dist/primitive-hooks/useActionBarCopy.d.ts.map +0 -1
  158. package/dist/primitive-hooks/useActionBarCopy.js +0 -26
  159. package/dist/primitive-hooks/useActionBarCopy.js.map +0 -1
  160. package/dist/primitive-hooks/useActionBarEdit.d.ts +0 -5
  161. package/dist/primitive-hooks/useActionBarEdit.d.ts.map +0 -1
  162. package/dist/primitive-hooks/useActionBarEdit.js +0 -11
  163. package/dist/primitive-hooks/useActionBarEdit.js.map +0 -1
  164. package/dist/primitive-hooks/useActionBarFeedback.d.ts +0 -9
  165. package/dist/primitive-hooks/useActionBarFeedback.d.ts.map +0 -1
  166. package/dist/primitive-hooks/useActionBarFeedback.js +0 -19
  167. package/dist/primitive-hooks/useActionBarFeedback.js.map +0 -1
  168. package/dist/primitive-hooks/useActionBarReload.d.ts +0 -5
  169. package/dist/primitive-hooks/useActionBarReload.d.ts.map +0 -1
  170. package/dist/primitive-hooks/useActionBarReload.js +0 -13
  171. package/dist/primitive-hooks/useActionBarReload.js.map +0 -1
  172. package/dist/primitive-hooks/useComposerAddAttachment.d.ts +0 -5
  173. package/dist/primitive-hooks/useComposerAddAttachment.d.ts.map +0 -1
  174. package/dist/primitive-hooks/useComposerAddAttachment.js +0 -10
  175. package/dist/primitive-hooks/useComposerAddAttachment.js.map +0 -1
  176. package/dist/primitive-hooks/useComposerCancel.d.ts +0 -5
  177. package/dist/primitive-hooks/useComposerCancel.d.ts.map +0 -1
  178. package/dist/primitive-hooks/useComposerCancel.js +0 -11
  179. package/dist/primitive-hooks/useComposerCancel.js.map +0 -1
  180. package/dist/primitive-hooks/useComposerSend.d.ts +0 -5
  181. package/dist/primitive-hooks/useComposerSend.d.ts.map +0 -1
  182. package/dist/primitive-hooks/useComposerSend.js +0 -11
  183. package/dist/primitive-hooks/useComposerSend.js.map +0 -1
  184. package/dist/primitive-hooks/useEditComposerCancel.d.ts +0 -4
  185. package/dist/primitive-hooks/useEditComposerCancel.d.ts.map +0 -1
  186. package/dist/primitive-hooks/useEditComposerCancel.js +0 -10
  187. package/dist/primitive-hooks/useEditComposerCancel.js.map +0 -1
  188. package/dist/primitive-hooks/useEditComposerSend.d.ts +0 -5
  189. package/dist/primitive-hooks/useEditComposerSend.d.ts.map +0 -1
  190. package/dist/primitive-hooks/useEditComposerSend.js +0 -11
  191. package/dist/primitive-hooks/useEditComposerSend.js.map +0 -1
  192. package/dist/primitive-hooks/useMessageBranching.d.ts +0 -7
  193. package/dist/primitive-hooks/useMessageBranching.d.ts.map +0 -1
  194. package/dist/primitive-hooks/useMessageBranching.js +0 -15
  195. package/dist/primitive-hooks/useMessageBranching.js.map +0 -1
  196. package/dist/primitive-hooks/useMessageReload.d.ts +0 -5
  197. package/dist/primitive-hooks/useMessageReload.d.ts.map +0 -1
  198. package/dist/primitive-hooks/useMessageReload.js +0 -11
  199. package/dist/primitive-hooks/useMessageReload.js.map +0 -1
  200. package/dist/primitive-hooks/useThreadIsEmpty.d.ts +0 -2
  201. package/dist/primitive-hooks/useThreadIsEmpty.d.ts.map +0 -1
  202. package/dist/primitive-hooks/useThreadIsEmpty.js +0 -5
  203. package/dist/primitive-hooks/useThreadIsEmpty.js.map +0 -1
  204. package/dist/primitive-hooks/useThreadIsRunning.d.ts +0 -2
  205. package/dist/primitive-hooks/useThreadIsRunning.d.ts.map +0 -1
  206. package/dist/primitive-hooks/useThreadIsRunning.js +0 -5
  207. package/dist/primitive-hooks/useThreadIsRunning.js.map +0 -1
  208. package/dist/primitive-hooks/useThreadMessages.d.ts +0 -3
  209. package/dist/primitive-hooks/useThreadMessages.d.ts.map +0 -1
  210. package/dist/primitive-hooks/useThreadMessages.js +0 -5
  211. package/dist/primitive-hooks/useThreadMessages.js.map +0 -1
  212. package/dist/primitives/composer/EditComposerCancel.d.ts +0 -7
  213. package/dist/primitives/composer/EditComposerCancel.d.ts.map +0 -1
  214. package/dist/primitives/composer/EditComposerCancel.js +0 -8
  215. package/dist/primitives/composer/EditComposerCancel.js.map +0 -1
  216. package/dist/primitives/composer/EditComposerInput.d.ts +0 -10
  217. package/dist/primitives/composer/EditComposerInput.d.ts.map +0 -1
  218. package/dist/primitives/composer/EditComposerInput.js +0 -19
  219. package/dist/primitives/composer/EditComposerInput.js.map +0 -1
  220. package/dist/primitives/composer/EditComposerSend.d.ts +0 -7
  221. package/dist/primitives/composer/EditComposerSend.d.ts.map +0 -1
  222. package/dist/primitives/composer/EditComposerSend.js +0 -8
  223. package/dist/primitives/composer/EditComposerSend.js.map +0 -1
  224. package/src/adapters/LocalStorageThreadListAdapter.tsx +0 -227
  225. package/src/adapters/TitleGenerationAdapter.ts +0 -20
  226. package/src/adapters/index.ts +0 -5
  227. package/src/primitive-hooks/index.ts +0 -20
  228. package/src/primitive-hooks/useActionBarCopy.ts +0 -38
  229. package/src/primitive-hooks/useActionBarEdit.ts +0 -13
  230. package/src/primitive-hooks/useActionBarFeedback.ts +0 -28
  231. package/src/primitive-hooks/useActionBarReload.ts +0 -18
  232. package/src/primitive-hooks/useComposerAddAttachment.ts +0 -16
  233. package/src/primitive-hooks/useComposerCancel.ts +0 -13
  234. package/src/primitive-hooks/useComposerSend.ts +0 -13
  235. package/src/primitive-hooks/useEditComposerCancel.ts +0 -12
  236. package/src/primitive-hooks/useEditComposerSend.ts +0 -13
  237. package/src/primitive-hooks/useMessageBranching.ts +0 -18
  238. package/src/primitive-hooks/useMessageReload.ts +0 -13
  239. package/src/primitive-hooks/useThreadIsEmpty.ts +0 -5
  240. package/src/primitive-hooks/useThreadIsRunning.ts +0 -5
  241. package/src/primitive-hooks/useThreadMessages.ts +0 -6
  242. package/src/primitives/composer/EditComposerCancel.tsx +0 -20
  243. package/src/primitives/composer/EditComposerInput.tsx +0 -40
  244. package/src/primitives/composer/EditComposerSend.tsx +0 -25
@@ -1,42 +1,137 @@
1
- import { type ReactElement } from "react";
1
+ import { type ComponentType, type FC, memo } from "react";
2
2
  import { Box } from "ink";
3
3
  import type { ThreadMessage } from "@assistant-ui/core";
4
- import { useAui, useAuiState, AuiProvider, Derived } from "@assistant-ui/store";
4
+ import { useAuiState } from "@assistant-ui/store";
5
+ import { MessageByIndexProvider } from "@assistant-ui/core/react";
6
+
7
+ type MessageComponents =
8
+ | {
9
+ Message: ComponentType;
10
+ EditComposer?: ComponentType | undefined;
11
+ UserEditComposer?: ComponentType | undefined;
12
+ AssistantEditComposer?: ComponentType | undefined;
13
+ SystemEditComposer?: ComponentType | undefined;
14
+ UserMessage?: ComponentType | undefined;
15
+ AssistantMessage?: ComponentType | undefined;
16
+ SystemMessage?: ComponentType | undefined;
17
+ }
18
+ | {
19
+ Message?: ComponentType | undefined;
20
+ EditComposer?: ComponentType | undefined;
21
+ UserEditComposer?: ComponentType | undefined;
22
+ AssistantEditComposer?: ComponentType | undefined;
23
+ SystemEditComposer?: ComponentType | undefined;
24
+ UserMessage: ComponentType;
25
+ AssistantMessage: ComponentType;
26
+ SystemMessage?: ComponentType | undefined;
27
+ };
5
28
 
6
29
  export type ThreadMessagesProps = {
7
- renderMessage: (props: {
8
- message: ThreadMessage;
9
- index: number;
10
- }) => ReactElement;
30
+ components: MessageComponents;
11
31
  };
12
32
 
13
- const MessageScope = ({
14
- index,
15
- children,
16
- }: {
17
- index: number;
18
- children: ReactElement;
33
+ const DEFAULT_SYSTEM_MESSAGE = () => null;
34
+
35
+ const getComponent = (
36
+ components: MessageComponents,
37
+ role: ThreadMessage["role"],
38
+ isEditing: boolean,
39
+ ) => {
40
+ switch (role) {
41
+ case "user":
42
+ if (isEditing) {
43
+ return (
44
+ components.UserEditComposer ??
45
+ components.EditComposer ??
46
+ components.UserMessage ??
47
+ (components.Message as ComponentType)
48
+ );
49
+ } else {
50
+ return components.UserMessage ?? (components.Message as ComponentType);
51
+ }
52
+ case "assistant":
53
+ if (isEditing) {
54
+ return (
55
+ components.AssistantEditComposer ??
56
+ components.EditComposer ??
57
+ components.AssistantMessage ??
58
+ (components.Message as ComponentType)
59
+ );
60
+ } else {
61
+ return (
62
+ components.AssistantMessage ?? (components.Message as ComponentType)
63
+ );
64
+ }
65
+ case "system":
66
+ if (isEditing) {
67
+ return (
68
+ components.SystemEditComposer ??
69
+ components.EditComposer ??
70
+ components.SystemMessage ??
71
+ (components.Message as ComponentType) ??
72
+ DEFAULT_SYSTEM_MESSAGE
73
+ );
74
+ } else {
75
+ return (
76
+ components.SystemMessage ??
77
+ (components.Message as ComponentType) ??
78
+ DEFAULT_SYSTEM_MESSAGE
79
+ );
80
+ }
81
+ default: {
82
+ const _exhaustiveCheck: never = role;
83
+ throw new Error(`Unknown message role: ${_exhaustiveCheck}`);
84
+ }
85
+ }
86
+ };
87
+
88
+ const ThreadMessageComponent: FC<{ components: MessageComponents }> = ({
89
+ components,
19
90
  }) => {
20
- const aui = useAui({
21
- message: Derived({
22
- source: "thread",
23
- query: { type: "index", index },
24
- get: (aui) => aui.threads().thread("main").message({ index }),
25
- }),
26
- });
27
-
28
- return <AuiProvider value={aui}>{children}</AuiProvider>;
91
+ const role = useAuiState((s) => s.message.role);
92
+ const isEditing = useAuiState((s) => s.message.composer.isEditing);
93
+ const Component = getComponent(components, role, isEditing);
94
+
95
+ return <Component />;
29
96
  };
30
97
 
31
- export const ThreadMessages = ({ renderMessage }: ThreadMessagesProps) => {
32
- const messages = useAuiState((s) => s.thread.messages);
98
+ const isComponentsSame = (prev: MessageComponents, next: MessageComponents) => {
99
+ return (
100
+ prev.Message === next.Message &&
101
+ prev.EditComposer === next.EditComposer &&
102
+ prev.UserEditComposer === next.UserEditComposer &&
103
+ prev.AssistantEditComposer === next.AssistantEditComposer &&
104
+ prev.SystemEditComposer === next.SystemEditComposer &&
105
+ prev.UserMessage === next.UserMessage &&
106
+ prev.AssistantMessage === next.AssistantMessage &&
107
+ prev.SystemMessage === next.SystemMessage
108
+ );
109
+ };
110
+
111
+ const ThreadMessageByIndex = memo(
112
+ ({ index, components }: { index: number; components: MessageComponents }) => {
113
+ return (
114
+ <MessageByIndexProvider index={index}>
115
+ <ThreadMessageComponent components={components} />
116
+ </MessageByIndexProvider>
117
+ );
118
+ },
119
+ (prev, next) =>
120
+ prev.index === next.index &&
121
+ isComponentsSame(prev.components, next.components),
122
+ );
123
+
124
+ export const ThreadMessages = ({ components }: ThreadMessagesProps) => {
125
+ const messagesLength = useAuiState((s) => s.thread.messages.length);
33
126
 
34
127
  return (
35
128
  <Box flexDirection="column">
36
- {(messages as unknown as ThreadMessage[]).map((message, index) => (
37
- <MessageScope key={message.id} index={index}>
38
- {renderMessage({ message, index })}
39
- </MessageScope>
129
+ {Array.from({ length: messagesLength }, (_, index) => (
130
+ <ThreadMessageByIndex
131
+ key={index}
132
+ index={index}
133
+ components={components}
134
+ />
40
135
  ))}
41
136
  </Box>
42
137
  );
@@ -1,16 +1,22 @@
1
- export { ThreadRoot, type ThreadRootProps } from "./ThreadRoot";
2
- export { ThreadMessages, type ThreadMessagesProps } from "./ThreadMessages";
3
1
  export {
4
- ThreadPrimitiveMessages,
5
- ThreadPrimitiveMessageByIndex,
6
- } from "@assistant-ui/core/react";
7
- export { ThreadEmpty, type ThreadEmptyProps } from "./ThreadEmpty";
8
- export { ThreadIf, type ThreadIfProps } from "./ThreadIf";
2
+ ThreadRoot as Root,
3
+ type ThreadRootProps as RootProps,
4
+ } from "./ThreadRoot";
5
+ export {
6
+ ThreadMessages as Messages,
7
+ type ThreadMessagesProps as MessagesProps,
8
+ } from "./ThreadMessages";
9
+ export { ThreadPrimitiveMessageByIndex as MessageByIndex } from "@assistant-ui/core/react";
10
+ export {
11
+ ThreadEmpty as Empty,
12
+ type ThreadEmptyProps as EmptyProps,
13
+ } from "./ThreadEmpty";
14
+ export { ThreadIf as If, type ThreadIfProps as IfProps } from "./ThreadIf";
9
15
  export {
10
- ThreadSuggestion,
11
- type ThreadSuggestionProps,
16
+ ThreadSuggestion as Suggestion,
17
+ type ThreadSuggestionProps as SuggestionProps,
12
18
  } from "./ThreadSuggestion";
13
19
  export {
14
- ThreadPrimitiveSuggestions,
15
- ThreadPrimitiveSuggestionByIndex,
20
+ ThreadPrimitiveSuggestions as Suggestions,
21
+ ThreadPrimitiveSuggestionByIndex as SuggestionByIndex,
16
22
  } from "@assistant-ui/core/react";
@@ -1,3 +1,12 @@
1
- export { ThreadListRoot, type ThreadListRootProps } from "./ThreadListRoot";
2
- export { ThreadListItems, type ThreadListItemsProps } from "./ThreadListItems";
3
- export { ThreadListNew, type ThreadListNewProps } from "./ThreadListNew";
1
+ export {
2
+ ThreadListRoot as Root,
3
+ type ThreadListRootProps as RootProps,
4
+ } from "./ThreadListRoot";
5
+ export {
6
+ ThreadListItems as Items,
7
+ type ThreadListItemsProps as ItemsProps,
8
+ } from "./ThreadListItems";
9
+ export {
10
+ ThreadListNew as New,
11
+ type ThreadListNewProps as NewProps,
12
+ } from "./ThreadListNew";
@@ -1,21 +1,21 @@
1
1
  export {
2
- ThreadListItemRoot,
3
- type ThreadListItemRootProps,
2
+ ThreadListItemRoot as Root,
3
+ type ThreadListItemRootProps as RootProps,
4
4
  } from "./ThreadListItemRoot";
5
- export { ThreadListItemPrimitiveTitle as ThreadListItemTitle } from "@assistant-ui/core/react";
5
+ export { ThreadListItemPrimitiveTitle as Title } from "@assistant-ui/core/react";
6
6
  export {
7
- ThreadListItemTrigger,
8
- type ThreadListItemTriggerProps,
7
+ ThreadListItemTrigger as Trigger,
8
+ type ThreadListItemTriggerProps as TriggerProps,
9
9
  } from "./ThreadListItemTrigger";
10
10
  export {
11
- ThreadListItemDelete,
12
- type ThreadListItemDeleteProps,
11
+ ThreadListItemDelete as Delete,
12
+ type ThreadListItemDeleteProps as DeleteProps,
13
13
  } from "./ThreadListItemDelete";
14
14
  export {
15
- ThreadListItemArchive,
16
- type ThreadListItemArchiveProps,
15
+ ThreadListItemArchive as Archive,
16
+ type ThreadListItemArchiveProps as ArchiveProps,
17
17
  } from "./ThreadListItemArchive";
18
18
  export {
19
- ThreadListItemUnarchive,
20
- type ThreadListItemUnarchiveProps,
19
+ ThreadListItemUnarchive as Unarchive,
20
+ type ThreadListItemUnarchiveProps as UnarchiveProps,
21
21
  } from "./ThreadListItemUnarchive";
@@ -0,0 +1,40 @@
1
+ import type { ReactElement } from "react";
2
+ import { afterEach, describe, expect, it } from "vitest";
3
+ import { cleanup, render } from "ink-testing-library";
4
+ import { ToolFallback } from "./ToolFallback";
5
+
6
+ const renderFrame = async (node: ReactElement) => {
7
+ const instance = render(node);
8
+ await new Promise((resolve) => setTimeout(resolve, 0));
9
+ return instance.lastFrame() ?? "";
10
+ };
11
+
12
+ afterEach(() => {
13
+ cleanup();
14
+ });
15
+
16
+ describe("ToolFallback", () => {
17
+ it("truncates expanded error output with maxResultLines", async () => {
18
+ const frame = await renderFrame(
19
+ <ToolFallback
20
+ expanded
21
+ maxResultLines={2}
22
+ type="tool-call"
23
+ toolCallId="tool-call-1"
24
+ toolName="search"
25
+ args={{}}
26
+ argsText="{}"
27
+ result={"line 1\nline 2\nline 3\nline 4"}
28
+ isError
29
+ status={{ type: "incomplete", reason: "error", error: "boom" }}
30
+ />,
31
+ );
32
+
33
+ expect(frame).toContain("Error:");
34
+ expect(frame).toContain("line 1");
35
+ expect(frame).toContain("line 2");
36
+ expect(frame).toContain("... (2 more lines)");
37
+ expect(frame).not.toContain("line 3");
38
+ expect(frame).not.toContain("line 4");
39
+ });
40
+ });
@@ -0,0 +1,227 @@
1
+ import { type ReactNode, useMemo } from "react";
2
+ import { Box, Text } from "ink";
3
+ import Spinner from "ink-spinner";
4
+ import type { ToolCallMessagePartStatus } from "@assistant-ui/core";
5
+ import type { ToolCallMessagePartProps } from "../../types";
6
+
7
+ export type ToolCallStatus =
8
+ | "running"
9
+ | "complete"
10
+ | "error"
11
+ | "requires-action";
12
+
13
+ type ToolFallbackBaseProps = Omit<
14
+ ToolCallMessagePartProps,
15
+ "addResult" | "resume"
16
+ > &
17
+ Partial<Pick<ToolCallMessagePartProps, "addResult" | "resume">>;
18
+
19
+ const STATUS_ICONS: Record<Exclude<ToolCallStatus, "running">, string> = {
20
+ complete: "+",
21
+ error: "x",
22
+ "requires-action": "?",
23
+ };
24
+
25
+ const STATUS_COLORS: Record<ToolCallStatus, string> = {
26
+ running: "yellow",
27
+ complete: "green",
28
+ error: "red",
29
+ "requires-action": "cyan",
30
+ };
31
+
32
+ const prettyPrintArgs = (argsText: string): string => {
33
+ if (!argsText) return "";
34
+ try {
35
+ return JSON.stringify(JSON.parse(argsText), null, 2);
36
+ } catch {
37
+ return argsText;
38
+ }
39
+ };
40
+
41
+ const formatResult = (result: unknown): string => {
42
+ if (result === undefined || result === null) return "";
43
+ if (typeof result === "string") return result;
44
+ try {
45
+ return JSON.stringify(result, null, 2);
46
+ } catch {
47
+ return String(result);
48
+ }
49
+ };
50
+
51
+ const truncate = (text: string, maxLines: number): string => {
52
+ const lines = text.split("\n");
53
+ if (lines.length <= maxLines) return text;
54
+ return (
55
+ lines.slice(0, maxLines).join("\n") +
56
+ `\n... (${lines.length - maxLines} more lines)`
57
+ );
58
+ };
59
+
60
+ export type ToolFallbackProps = ToolFallbackBaseProps & {
61
+ /** Force expanded or collapsed. When unset, auto-expands while running, awaiting action, or errored. */
62
+ expanded?: boolean;
63
+ /** Maximum lines to show for args when expanded. Defaults to 20. */
64
+ maxArgLines?: number;
65
+ /** Maximum lines to show for result when expanded. Defaults to 20. */
66
+ maxResultLines?: number;
67
+ /** Maximum lines to show for result preview when collapsed. Defaults to 1. */
68
+ maxResultPreviewLines?: number;
69
+ /** Custom header renderer */
70
+ renderHeader?: (props: {
71
+ toolName: string;
72
+ status: ToolCallStatus;
73
+ expanded: boolean;
74
+ }) => ReactNode;
75
+ /** Custom args renderer */
76
+ renderArgs?: (props: { args: unknown; argsText: string }) => ReactNode;
77
+ /** Custom result renderer */
78
+ renderResult?: (props: { result: unknown; isError: boolean }) => ReactNode;
79
+ };
80
+
81
+ const resolveStatus = (
82
+ part: {
83
+ interrupt: unknown;
84
+ isError: boolean | undefined;
85
+ result: unknown;
86
+ },
87
+ status?: ToolCallMessagePartStatus,
88
+ ): ToolCallStatus => {
89
+ if (status?.type === "requires-action") return "requires-action";
90
+ if (status?.type === "incomplete") return "error";
91
+ if (status?.type === "complete") return "complete";
92
+ if (part.isError) return "error";
93
+ if (part.result !== undefined) return "complete";
94
+ if (part.interrupt) return "requires-action";
95
+ return "running";
96
+ };
97
+
98
+ const getDisplayResult = (
99
+ result: unknown,
100
+ status?: ToolCallMessagePartStatus,
101
+ ) => {
102
+ if (result !== undefined) return result;
103
+ if (status?.type === "incomplete") return status.error;
104
+ return undefined;
105
+ };
106
+
107
+ const getFallbackErrorText = (status?: ToolCallMessagePartStatus) => {
108
+ if (status?.type === "incomplete" && status.reason === "cancelled") {
109
+ return "Tool call cancelled";
110
+ }
111
+ return "Tool call failed";
112
+ };
113
+
114
+ const StatusIcon = ({ status }: { status: ToolCallStatus }) => {
115
+ if (status === "running") {
116
+ return (
117
+ <Text color={STATUS_COLORS.running}>
118
+ <Spinner type="line" />
119
+ </Text>
120
+ );
121
+ }
122
+ return <Text color={STATUS_COLORS[status]}>{STATUS_ICONS[status]}</Text>;
123
+ };
124
+
125
+ export const ToolFallback = ({
126
+ toolName,
127
+ args,
128
+ argsText,
129
+ result: partResult,
130
+ isError,
131
+ interrupt,
132
+ status,
133
+ expanded: expandedProp,
134
+ maxArgLines = 20,
135
+ maxResultLines = 20,
136
+ maxResultPreviewLines = 1,
137
+ renderHeader,
138
+ renderArgs,
139
+ renderResult,
140
+ }: ToolFallbackProps) => {
141
+ const displayStatus = resolveStatus(
142
+ {
143
+ interrupt,
144
+ isError,
145
+ result: partResult,
146
+ },
147
+ status,
148
+ );
149
+ const expanded =
150
+ expandedProp ??
151
+ (displayStatus === "running" ||
152
+ displayStatus === "requires-action" ||
153
+ displayStatus === "error");
154
+
155
+ const result = getDisplayResult(partResult, status);
156
+ const resultStr =
157
+ result !== undefined || displayStatus === "error"
158
+ ? formatResult(result)
159
+ : "";
160
+ const argsDisplay = useMemo(() => prettyPrintArgs(argsText), [argsText]);
161
+
162
+ return (
163
+ <Box flexDirection="column">
164
+ <Box gap={1}>
165
+ {renderHeader ? (
166
+ renderHeader({
167
+ toolName,
168
+ status: displayStatus,
169
+ expanded,
170
+ })
171
+ ) : (
172
+ <>
173
+ <StatusIcon status={displayStatus} />
174
+ <Text bold>{toolName}</Text>
175
+ {!expanded && resultStr ? (
176
+ <Text dimColor>{truncate(resultStr, maxResultPreviewLines)}</Text>
177
+ ) : null}
178
+ </>
179
+ )}
180
+ </Box>
181
+
182
+ {expanded && (
183
+ <Box flexDirection="column" marginLeft={2}>
184
+ {argsText ? (
185
+ <Box flexDirection="column">
186
+ <Text dimColor>Args:</Text>
187
+ {renderArgs ? (
188
+ renderArgs({ args, argsText })
189
+ ) : (
190
+ <Text>{truncate(argsDisplay, maxArgLines)}</Text>
191
+ )}
192
+ </Box>
193
+ ) : null}
194
+
195
+ {partResult !== undefined || displayStatus === "error" ? (
196
+ <Box flexDirection="column">
197
+ <Text dimColor>
198
+ {displayStatus === "error" ? "Error:" : "Result:"}
199
+ </Text>
200
+ {renderResult ? (
201
+ renderResult({
202
+ result,
203
+ isError: displayStatus === "error",
204
+ })
205
+ ) : displayStatus === "error" ? (
206
+ <Text color="red">
207
+ {truncate(
208
+ resultStr || getFallbackErrorText(status),
209
+ maxResultLines,
210
+ )}
211
+ </Text>
212
+ ) : (
213
+ <Text>{truncate(resultStr, maxResultLines)}</Text>
214
+ )}
215
+ </Box>
216
+ ) : null}
217
+
218
+ {displayStatus === "running" && <Text dimColor>Running...</Text>}
219
+
220
+ {displayStatus === "requires-action" && (
221
+ <Text color="cyan">Waiting for approval...</Text>
222
+ )}
223
+ </Box>
224
+ )}
225
+ </Box>
226
+ );
227
+ };
@@ -0,0 +1,5 @@
1
+ export {
2
+ ToolFallback as Fallback,
3
+ type ToolFallbackProps as FallbackProps,
4
+ type ToolCallStatus,
5
+ } from "./ToolFallback";