@superinterface/react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/package.json +41 -0
  2. package/src/components/examples/Examples/Example/index.tsx +65 -0
  3. package/src/components/examples/Examples/index.tsx +85 -0
  4. package/src/components/messageGroups/MessagesGroupBase/AssistantAvatar.tsx +18 -0
  5. package/src/components/messageGroups/MessagesGroupBase/Name.tsx +24 -0
  6. package/src/components/messageGroups/MessagesGroupBase/index.tsx +29 -0
  7. package/src/components/messages/Form/Submit/index.tsx +29 -0
  8. package/src/components/messages/Form/index.tsx +150 -0
  9. package/src/components/messages/Message/TextContent/index.tsx +22 -0
  10. package/src/components/messages/Message/index.tsx +71 -0
  11. package/src/components/messages/Messages/Content/MessageGroup/Content/index.tsx +22 -0
  12. package/src/components/messages/Messages/Content/MessageGroup/index.tsx +47 -0
  13. package/src/components/messages/Messages/Content/index.tsx +26 -0
  14. package/src/components/messages/Messages/ProgressMessage/index.tsx +31 -0
  15. package/src/components/messages/Messages/index.tsx +102 -0
  16. package/src/components/runSteps/RunStep/ToolCalls/Starting/index.tsx +28 -0
  17. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/CodeInterpreter/index.tsx +17 -0
  18. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/Availabilities/Title.tsx +29 -0
  19. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/Availabilities/index.tsx +34 -0
  20. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/Content/index.tsx +58 -0
  21. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/Icon.tsx +28 -0
  22. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/Scores/Title.tsx +29 -0
  23. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/Scores/index.tsx +34 -0
  24. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/Fn/index.tsx +31 -0
  25. package/src/components/runSteps/RunStep/ToolCalls/ToolCall/index.tsx +44 -0
  26. package/src/components/runSteps/RunStep/ToolCalls/index.tsx +31 -0
  27. package/src/components/runSteps/RunStep/index.tsx +21 -0
  28. package/src/components/runSteps/RunSteps/index.tsx +22 -0
  29. package/src/components/skeletons/MessagesSkeleton/index.tsx +50 -0
  30. package/src/components/skeletons/RunSkeleton/index.tsx +34 -0
  31. package/src/components/skeletons/Skeleton/index.tsx +17 -0
  32. package/src/components/skeletons/StartingContentSkeleton/index.tsx +13 -0
  33. package/src/components/skeletons/StartingSkeleton/index.tsx +33 -0
  34. package/src/components/spinners/Spinner/index.tsx +17 -0
  35. package/src/components/textareas/TextareaBase/index.tsx +28 -0
  36. package/src/components/toolCalls/ToolCallBase/ToolCallTitle.tsx +17 -0
  37. package/src/components/toolCalls/ToolCallBase/index.tsx +34 -0
  38. package/src/contexts/assistants/AssistantNameContext/index.tsx +3 -0
  39. package/src/contexts/avatars/AssistantAvatarContext/index.tsx +14 -0
  40. package/src/contexts/markdown/MarkdownContext/index.ts +7 -0
  41. package/src/contexts/markdown/MarkdownContext/lib/components/Link.tsx +13 -0
  42. package/src/contexts/markdown/MarkdownContext/lib/components/ListItem.tsx +13 -0
  43. package/src/contexts/markdown/MarkdownContext/lib/components/OrderedList.tsx +16 -0
  44. package/src/contexts/markdown/MarkdownContext/lib/components/Paragraph.tsx +17 -0
  45. package/src/contexts/markdown/MarkdownContext/lib/components/Strong.tsx +9 -0
  46. package/src/contexts/markdown/MarkdownContext/lib/components/UnorderedList.tsx +16 -0
  47. package/src/contexts/markdown/MarkdownContext/lib/components/index.tsx +16 -0
  48. package/src/hooks/actions/useHandleAction/index.tsx +30 -0
  49. package/src/hooks/actions/useHandleAction/lib/mutationOptions/index.ts +14 -0
  50. package/src/hooks/actions/useHandleAction/lib/mutationOptions/mutationFn/index.ts +39 -0
  51. package/src/hooks/actions/useHandleAction/lib/mutationOptions/mutationFn/toolOutput/index.ts +29 -0
  52. package/src/hooks/actions/useHandleAction/lib/mutationOptions/onSettled.ts +22 -0
  53. package/src/hooks/actions/useManageActions/index.tsx +43 -0
  54. package/src/hooks/messageGroups/useMessageGroups/index.ts +18 -0
  55. package/src/hooks/messageGroups/useMessageGroups/lib/messageGroups/index.ts +37 -0
  56. package/src/hooks/messageGroups/useMessageGroups/lib/messageGroups/newGroup/index.ts +14 -0
  57. package/src/hooks/messageGroups/useMessageGroups/lib/messageGroups/newGroup/newGroupItem.ts +12 -0
  58. package/src/hooks/messages/useCreateMessage/index.ts +30 -0
  59. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/index.ts +24 -0
  60. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/mutationFn.ts +25 -0
  61. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/onError.ts +27 -0
  62. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/onMutate/data.ts +62 -0
  63. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/onMutate/index.ts +25 -0
  64. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/onSettled.ts +16 -0
  65. package/src/hooks/messages/useCreateMessage/lib/mutationOptions/onSuccess.ts +48 -0
  66. package/src/hooks/messages/useLatestMessage/index.ts +20 -0
  67. package/src/hooks/messages/useMessages/index.tsx +41 -0
  68. package/src/hooks/messages/useMessages/lib/queryOptions/index.ts +20 -0
  69. package/src/hooks/messages/useMessages/lib/queryOptions/queryFn/data/index.ts +32 -0
  70. package/src/hooks/messages/useMessages/lib/queryOptions/queryFn/data/runMessages/getLatestRun.ts +15 -0
  71. package/src/hooks/messages/useMessages/lib/queryOptions/queryFn/data/runMessages/index.ts +44 -0
  72. package/src/hooks/messages/useMessages/lib/queryOptions/queryFn/hasNextPage.ts +12 -0
  73. package/src/hooks/messages/useMessages/lib/queryOptions/queryFn/index.ts +32 -0
  74. package/src/hooks/messages/useMessages/lib/queryOptions/queryFn/messagesLimit.ts +1 -0
  75. package/src/hooks/messages/useMessages/lib/queryOptions/queryKey.ts +3 -0
  76. package/src/hooks/misc/useInfiniteScroll/index.tsx +42 -0
  77. package/src/hooks/misc/useThrottledEffect/index.tsx +19 -0
  78. package/src/hooks/runs/useCreateRun/index.ts +30 -0
  79. package/src/hooks/runs/useCreateRun/lib/mutationOptions/index.ts +16 -0
  80. package/src/hooks/runs/useCreateRun/lib/mutationOptions/mutationFn.ts +30 -0
  81. package/src/hooks/runs/useCreateRun/lib/mutationOptions/onSettled.ts +22 -0
  82. package/src/hooks/runs/useCreateRun/lib/mutationOptions/onSuccess.ts +44 -0
  83. package/src/hooks/runs/useIsRunActive/index.tsx +65 -0
  84. package/src/hooks/runs/useLatestRun/index.ts +20 -0
  85. package/src/hooks/runs/useManageRuns/index.tsx +55 -0
  86. package/src/hooks/runs/usePolling/index.tsx +39 -0
  87. package/src/hooks/runs/usePolling/lib/refetch.ts +20 -0
  88. package/src/hooks/runs/useRuns/index.tsx +27 -0
  89. package/src/hooks/runs/useRuns/lib/getRuns.ts +16 -0
  90. package/src/hooks/runs/useRuns/lib/queryOptions/index.ts +21 -0
  91. package/src/hooks/runs/useRuns/lib/queryOptions/queryFn.ts +22 -0
  92. package/src/hooks/runs/useRuns/lib/queryOptions/queryKey.ts +3 -0
  93. package/src/hooks/threads/useThreadLifecycles/index.tsx +41 -0
  94. package/src/index.ts +12 -0
  95. package/src/lib/ai/index.ts +15 -0
  96. package/src/lib/index.ts +1 -0
  97. package/src/lib/messages/extendMessage.ts +25 -0
  98. package/src/lib/messages/order.ts +9 -0
  99. package/src/lib/optimistic/isOptimistic.ts +11 -0
  100. package/src/lib/optimistic/optimisticId.ts +5 -0
  101. package/src/lib/runSteps/getRunSteps/index.ts +18 -0
  102. package/src/lib/runs/isRunEditingMessage/index.ts +21 -0
  103. package/src/mutationFns.ts +3 -0
  104. package/src/queryFns.ts +2 -0
  105. package/src/queryKeys.ts +2 -0
  106. package/src/types/index.ts +38 -0
  107. package/tsconfig.json +10 -0
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@superinterface/react",
3
+ "version": "1.0.0",
4
+ "main": "./dist/index.js",
5
+ "exports": {
6
+ ".": "./dist/index.js",
7
+ "./*": "./dist/*.js",
8
+ "./types": "./dist/types/index.js",
9
+ "./lib": "./dist/lib/index.js"
10
+ },
11
+ "keywords": [],
12
+ "license": "ISC",
13
+ "scripts": {
14
+ "resolve-tspaths": "resolve-tspaths",
15
+ "install-peers": "install-peers"
16
+ },
17
+ "dependencies": {
18
+ "@hookform/resolvers": "^3.3.3",
19
+ "@radix-ui/react-icons": "^1.3.0",
20
+ "@radix-ui/themes": "^2.0.3",
21
+ "lodash": "^4.17.21",
22
+ "openai": "^4.24.1",
23
+ "p-map": "^7.0.1",
24
+ "radash": "^11.0.0",
25
+ "react-hook-form": "^7.49.2",
26
+ "react-intersection-observer": "^9.5.3",
27
+ "react-markdown": "^9.0.1",
28
+ "react-textarea-autosize": "^8.5.3",
29
+ "react-use": "^17.4.2",
30
+ "zod": "^3.22.4"
31
+ },
32
+ "peerDependencies": {
33
+ "react": "^18"
34
+ },
35
+ "devDependencies": {
36
+ "@types/lodash": "^4.14.202",
37
+ "@types/react": "^18.2.46",
38
+ "install-peers-cli": "^2.2.0",
39
+ "resolve-tspaths": "^0.8.17"
40
+ }
41
+ }
@@ -0,0 +1,65 @@
1
+ import {
2
+ UseMutationOptions,
3
+ UseInfiniteQueryOptions,
4
+ InfiniteData,
5
+ } from '@tanstack/react-query'
6
+ import {
7
+ ArrowUpIcon,
8
+ } from '@radix-ui/react-icons'
9
+ import {
10
+ Text,
11
+ Button,
12
+ } from '@radix-ui/themes'
13
+ import { useCreateMessage } from '@/hooks/messages/useCreateMessage'
14
+ import { useIsRunActive } from '@/hooks/runs/useIsRunActive'
15
+ import { Message, MessagesPage, RunsPage } from '@/types'
16
+
17
+ type Args = {
18
+ example: string
19
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
20
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
21
+ createMessageMutationOptions: UseMutationOptions<{ message: Message }>
22
+ }
23
+
24
+ export const Example = ({
25
+ example,
26
+ messagesQueryOptions,
27
+ runsQueryOptions,
28
+ createMessageMutationOptions,
29
+ }: Args) => {
30
+ const {
31
+ createMessage,
32
+ } = useCreateMessage({
33
+ createMessageMutationOptions,
34
+ })
35
+
36
+ const { isRunActive } = useIsRunActive({
37
+ messagesQueryOptions,
38
+ runsQueryOptions,
39
+ })
40
+
41
+ return (
42
+ <Button
43
+ variant="soft"
44
+ style={{
45
+ justifyContent: 'space-between',
46
+ }}
47
+ onClick={() => {
48
+ // @ts-ignore-next-line
49
+ createMessage({
50
+ content: example,
51
+ })
52
+ }}
53
+ disabled={isRunActive}
54
+ >
55
+ <Text
56
+ size="1"
57
+ weight="regular"
58
+ >
59
+ {example}
60
+ </Text>
61
+
62
+ <ArrowUpIcon />
63
+ </Button>
64
+ )
65
+ }
@@ -0,0 +1,85 @@
1
+ import {
2
+ UseMutationOptions,
3
+ UseInfiniteQueryOptions,
4
+ InfiniteData,
5
+ } from '@tanstack/react-query'
6
+ import {
7
+ Grid,
8
+ } from '@radix-ui/themes'
9
+ import { Message, MessagesPage, RunsPage } from '@/types'
10
+ import { Example } from './Example'
11
+
12
+ type Args = {
13
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
14
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
15
+ createMessageMutationOptions: UseMutationOptions<{ message: Message }>
16
+ latestMessage: Message | null
17
+ isLoading: boolean
18
+ }
19
+
20
+ const initialExamples = [
21
+ 'Find a brandable domain for an AI cooking app.',
22
+ 'Create a domain name for a todo app.',
23
+ 'Suggest a domain for a financial tech startup.',
24
+ 'Luxurious .com domain for a space company.',
25
+ ]
26
+
27
+ const regularExamples = [
28
+ 'Continue',
29
+ ]
30
+
31
+ export const Examples = ({
32
+ createMessageMutationOptions,
33
+ messagesQueryOptions,
34
+ runsQueryOptions,
35
+ latestMessage,
36
+ isLoading,
37
+ }: Args) => {
38
+ if (!latestMessage) {
39
+ return (
40
+ <Grid
41
+ columns={{
42
+ initial: "1",
43
+ md: "2",
44
+ }}
45
+ gap="2"
46
+ py="2"
47
+ >
48
+ {initialExamples.map((example) => (
49
+ <Example
50
+ key={example}
51
+ example={example}
52
+ createMessageMutationOptions={createMessageMutationOptions}
53
+ messagesQueryOptions={messagesQueryOptions}
54
+ runsQueryOptions={runsQueryOptions}
55
+ />
56
+ ))}
57
+ </Grid>
58
+ )
59
+ }
60
+
61
+ if (latestMessage.role === 'assistant' && !isLoading) {
62
+ return (
63
+ <Grid
64
+ columns={{
65
+ initial: "3",
66
+ md: "4",
67
+ }}
68
+ gap="2"
69
+ py="2"
70
+ >
71
+ {regularExamples.map((example) => (
72
+ <Example
73
+ key={example}
74
+ example={example}
75
+ createMessageMutationOptions={createMessageMutationOptions}
76
+ messagesQueryOptions={messagesQueryOptions}
77
+ runsQueryOptions={runsQueryOptions}
78
+ />
79
+ ))}
80
+ </Grid>
81
+ )
82
+ }
83
+
84
+ return null
85
+ }
@@ -0,0 +1,18 @@
1
+ import { useContext } from 'react'
2
+ import {
3
+ Flex,
4
+ } from '@radix-ui/themes'
5
+ import { AssistantAvatarContext } from '@/contexts/avatars/AssistantAvatarContext'
6
+
7
+ export const AssistantAvatar = () => {
8
+ const AssistantAvatarContextValue = useContext(AssistantAvatarContext)
9
+
10
+ return (
11
+ <Flex
12
+ shrink="0"
13
+ className="rounded-3 overflow-hidden h-[24px] w-[24px]"
14
+ >
15
+ {AssistantAvatarContextValue}
16
+ </Flex>
17
+ )
18
+ }
@@ -0,0 +1,24 @@
1
+ import {
2
+ Flex,
3
+ Text,
4
+ } from '@radix-ui/themes'
5
+
6
+ type Args = {
7
+ children: React.ReactNode
8
+ }
9
+
10
+ export const Name = ({
11
+ children,
12
+ }: Args) => (
13
+ <Flex
14
+ height="5"
15
+ align="center"
16
+ >
17
+ <Text
18
+ size="2"
19
+ weight="bold"
20
+ >
21
+ {children}
22
+ </Text>
23
+ </Flex>
24
+ )
@@ -0,0 +1,29 @@
1
+ import { forwardRef } from 'react'
2
+ import {
3
+ Flex,
4
+ Container,
5
+ } from '@radix-ui/themes'
6
+
7
+ type Args = {
8
+ children: React.ReactNode
9
+ }
10
+
11
+ export const MessagesGroupBase = forwardRef(function MessagesGroupBase({
12
+ children,
13
+ }: Args, ref) {
14
+ return (
15
+ <Container
16
+ // @ts-ignore-next-line
17
+ ref={ref}
18
+ size="2"
19
+ grow="0"
20
+ >
21
+ <Flex
22
+ shrink="0"
23
+ gap="3"
24
+ >
25
+ {children}
26
+ </Flex>
27
+ </Container>
28
+ )
29
+ })
@@ -0,0 +1,29 @@
1
+ import {
2
+ ArrowUpIcon,
3
+ } from '@radix-ui/react-icons'
4
+ import {
5
+ Button,
6
+ } from '@radix-ui/themes'
7
+ import {
8
+ Spinner,
9
+ } from '@/components/spinners/Spinner'
10
+
11
+ type Args = {
12
+ isLoading: boolean
13
+ isDisabled: boolean
14
+ }
15
+
16
+ export const Submit = ({
17
+ isLoading,
18
+ isDisabled
19
+ }: Args) => (
20
+ <Button
21
+ type="submit"
22
+ color="gray"
23
+ highContrast
24
+ radius="large"
25
+ disabled={isLoading || isDisabled}
26
+ >
27
+ {isLoading ? <Spinner /> : <ArrowUpIcon />}
28
+ </Button>
29
+ )
@@ -0,0 +1,150 @@
1
+ import {
2
+ UseInfiniteQueryOptions,
3
+ UseMutationOptions,
4
+ InfiniteData,
5
+ } from '@tanstack/react-query'
6
+ import {
7
+ Container,
8
+ Flex,
9
+ Text,
10
+ } from '@radix-ui/themes'
11
+ import { useMemo, useContext } from 'react'
12
+ import { Submit } from './Submit'
13
+ import { useIsRunActive } from '@/hooks/runs/useIsRunActive'
14
+ import { useForm, SubmitHandler } from 'react-hook-form'
15
+ import { z } from 'zod'
16
+ import { zodResolver } from '@hookform/resolvers/zod'
17
+ import { TextareaBase } from '@/components/textareas/TextareaBase'
18
+ import { useLatestMessage } from '@/hooks/messages/useLatestMessage'
19
+ import { useCreateMessage } from '@/hooks/messages/useCreateMessage'
20
+ import { AssistantNameContext } from '@/contexts/assistants/AssistantNameContext'
21
+ import { MessagesPage, RunsPage, Message } from '@/types'
22
+
23
+ export const schema = z.object({
24
+ content: z.string().min(1).max(300),
25
+ })
26
+
27
+ type Args = {
28
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
29
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
30
+ createMessageMutationOptions: UseMutationOptions<{ message: Message }>
31
+ }
32
+
33
+ type Inputs = {
34
+ content: string
35
+ }
36
+
37
+ export const Form = ({
38
+ messagesQueryOptions,
39
+ runsQueryOptions,
40
+ createMessageMutationOptions,
41
+ }: Args) => {
42
+ const {
43
+ register,
44
+ handleSubmit,
45
+ formState: { errors, isSubmitting },
46
+ reset,
47
+ } = useForm<Inputs>({
48
+ resolver: zodResolver(schema),
49
+ })
50
+
51
+ const { isRunActive } = useIsRunActive({
52
+ messagesQueryOptions,
53
+ runsQueryOptions,
54
+ })
55
+
56
+ const isLoading = useMemo(() => (
57
+ isRunActive || isSubmitting
58
+ ), [
59
+ isRunActive,
60
+ isSubmitting,
61
+ ])
62
+
63
+ const {
64
+ createMessage,
65
+ } = useCreateMessage({
66
+ createMessageMutationOptions,
67
+ })
68
+
69
+ const onSubmit: SubmitHandler<Inputs> = async (data) => {
70
+ reset()
71
+ // @ts-ignore-next-line
72
+ await createMessage({
73
+ content: data.content,
74
+ })
75
+ }
76
+
77
+ const { latestMessage } = useLatestMessage({
78
+ messagesQueryOptions,
79
+ })
80
+
81
+ const isDisabled = useMemo(() => (
82
+ // @ts-ignore-next-line
83
+ latestMessage?.metadata?.isBlocking
84
+ ), [latestMessage])
85
+
86
+ const assistantNameContext = useContext(AssistantNameContext)
87
+
88
+ return (
89
+ <Container
90
+ size="2"
91
+ px="2"
92
+ grow="0"
93
+ >
94
+ <Flex
95
+ direction="column"
96
+ shrink="0"
97
+ >
98
+ <Flex
99
+ direction="column"
100
+ shrink="0"
101
+ className="bg-gray-1"
102
+ pb="4"
103
+ >
104
+ <form
105
+ onSubmit={handleSubmit(onSubmit)}
106
+ >
107
+ <Flex
108
+ className={`rounded-3 border-gray-5 border border-solid ${errors.content ? 'border-red-9 bg-red-2' : ''}`}
109
+ p="2"
110
+ pl="4"
111
+ >
112
+ <Text
113
+ size="2"
114
+ className="grow"
115
+ >
116
+ <Flex
117
+ grow="1"
118
+ direction="column"
119
+ >
120
+ <TextareaBase
121
+ minRows={1}
122
+ placeholder={`Message ${assistantNameContext}...`}
123
+ disabled={isLoading || isDisabled}
124
+ onKeyDown={(e: any) => {
125
+ if (e.key === 'Enter' && !e.shiftKey) {
126
+ e.preventDefault()
127
+ handleSubmit(onSubmit)()
128
+ }
129
+ }}
130
+ {...register('content')}
131
+ />
132
+ </Flex>
133
+ </Text>
134
+
135
+ <Flex
136
+ shrink="0"
137
+ align="end"
138
+ >
139
+ <Submit
140
+ isLoading={isLoading}
141
+ isDisabled={isDisabled}
142
+ />
143
+ </Flex>
144
+ </Flex>
145
+ </form>
146
+ </Flex>
147
+ </Flex>
148
+ </Container>
149
+ )
150
+ }
@@ -0,0 +1,22 @@
1
+ import { useContext } from 'react'
2
+ import OpenAI from 'openai'
3
+ import Markdown from 'react-markdown'
4
+ import { MarkdownContext } from '@/contexts/markdown/MarkdownContext'
5
+
6
+ type Args = {
7
+ content: OpenAI.Beta.Threads.Messages.MessageContentText
8
+ }
9
+
10
+ export const TextContent = ({
11
+ content,
12
+ }: Args) => {
13
+ const markdownContext = useContext(MarkdownContext)
14
+
15
+ return (
16
+ <Markdown
17
+ {...markdownContext}
18
+ >
19
+ {content.text.value}
20
+ </Markdown>
21
+ )
22
+ }
@@ -0,0 +1,71 @@
1
+ import _ from 'lodash'
2
+ import { useMemo } from 'react'
3
+ import {
4
+ Box,
5
+ } from '@radix-ui/themes'
6
+ import { Message as MessageType } from '@/types'
7
+ import { RunSteps } from '@/components/runSteps/RunSteps'
8
+ import { TextContent } from './TextContent'
9
+
10
+ type Args = {
11
+ message: MessageType
12
+ }
13
+
14
+ export const Message = ({
15
+ message,
16
+ }: Args) => {
17
+ const [olderRunSteps, laterRunSteps] = useMemo(() => {
18
+ if (!message.runSteps.length) return [[], []]
19
+
20
+ const messageCreationRunStepIndex = message.runSteps.findIndex((runStep) => {
21
+ if (runStep.step_details.type !== 'message_creation') return
22
+
23
+ return runStep.step_details.message_creation.message_id === message.id
24
+ })
25
+
26
+ let nextRunStepIndex = message.runSteps.slice(0, messageCreationRunStepIndex).findLastIndex((runStep) => (
27
+ runStep.step_details.type === 'message_creation'
28
+ ))
29
+ if (nextRunStepIndex === -1) {
30
+ nextRunStepIndex = 0
31
+ }
32
+ const laterRunSteps = message.runSteps.slice(nextRunStepIndex, messageCreationRunStepIndex)
33
+
34
+ const prevRunStepIndex = message.runSteps.slice(messageCreationRunStepIndex + 1).findIndex((runStep) => (
35
+ runStep.step_details.type === 'message_creation'
36
+ ))
37
+
38
+ let olderRunSteps
39
+
40
+ if (prevRunStepIndex === -1) {
41
+ olderRunSteps = message.runSteps.slice(messageCreationRunStepIndex + 1)
42
+ } else {
43
+ olderRunSteps = message.runSteps.slice(messageCreationRunStepIndex + 1, messageCreationRunStepIndex + prevRunStepIndex)
44
+ }
45
+
46
+ return [olderRunSteps, laterRunSteps]
47
+
48
+ }, [message])
49
+
50
+ return (
51
+ <Box>
52
+ <RunSteps
53
+ runSteps={olderRunSteps}
54
+ />
55
+
56
+ {message.content.map((content, index) => (
57
+ <Box
58
+ key={index}
59
+ >
60
+ {content.type === 'text' && (
61
+ <TextContent content={content} />
62
+ )}
63
+ </Box>
64
+ ))}
65
+
66
+ <RunSteps
67
+ runSteps={laterRunSteps}
68
+ />
69
+ </Box>
70
+ )
71
+ }
@@ -0,0 +1,22 @@
1
+ import { Flex } from '@radix-ui/themes'
2
+ import { MessageGroup } from '@/types'
3
+ import { Message } from '@/components/messages/Message'
4
+
5
+ type Args = {
6
+ messageGroup: MessageGroup
7
+ }
8
+
9
+ export const Content = ({
10
+ messageGroup,
11
+ }: Args) => (
12
+ <Flex
13
+ direction="column-reverse"
14
+ >
15
+ {messageGroup.messages.map((message) => (
16
+ <Message
17
+ key={message.id}
18
+ message={message}
19
+ />
20
+ ))}
21
+ </Flex>
22
+ )
@@ -0,0 +1,47 @@
1
+ import { useContext } from 'react'
2
+ import {
3
+ Box,
4
+ Avatar,
5
+ } from '@radix-ui/themes'
6
+ import {
7
+ PersonIcon,
8
+ } from '@radix-ui/react-icons'
9
+ import { MessagesGroupBase } from '@/components/messageGroups/MessagesGroupBase'
10
+ import { Name } from '@/components/messageGroups/MessagesGroupBase/Name'
11
+ import { AssistantAvatar } from '@/components/messageGroups/MessagesGroupBase/AssistantAvatar'
12
+ import { AssistantNameContext } from '@/contexts/assistants/AssistantNameContext'
13
+ import { MessageGroup as MessageGroupType } from '@/types'
14
+ import { Content } from './Content'
15
+
16
+ type Args = {
17
+ messageGroup: MessageGroupType
18
+ }
19
+
20
+ export const MessageGroup = ({
21
+ messageGroup,
22
+ }: Args) => {
23
+ const assistantNameContext = useContext(AssistantNameContext)
24
+
25
+ return (
26
+ <MessagesGroupBase>
27
+ {messageGroup.role === 'user' ? (
28
+ <Avatar
29
+ fallback={<PersonIcon />}
30
+ size="1"
31
+ />
32
+ ) : (
33
+ <AssistantAvatar />
34
+ )}
35
+
36
+ <Box>
37
+ <Name>
38
+ {messageGroup.role === 'user' ? 'You' : assistantNameContext}
39
+ </Name>
40
+
41
+ <Content
42
+ messageGroup={messageGroup}
43
+ />
44
+ </Box>
45
+ </MessagesGroupBase>
46
+ )
47
+ }
@@ -0,0 +1,26 @@
1
+ import { useMessageGroups } from '@/hooks/messageGroups/useMessageGroups'
2
+ import { Message } from '@/types'
3
+ import { MessageGroup } from './MessageGroup'
4
+
5
+ type Args = {
6
+ messages: Message[]
7
+ }
8
+
9
+ export const Content = ({
10
+ messages,
11
+ }: Args) => {
12
+ const { messageGroups } = useMessageGroups({
13
+ messages,
14
+ })
15
+
16
+ return (
17
+ <>
18
+ {messageGroups.map((messageGroup) => (
19
+ <MessageGroup
20
+ key={messageGroup.id}
21
+ messageGroup={messageGroup}
22
+ />
23
+ ))}
24
+ </>
25
+ )
26
+ }
@@ -0,0 +1,31 @@
1
+ import { Box } from '@radix-ui/themes'
2
+ import { MessagesGroupBase } from '@/components/messageGroups/MessagesGroupBase'
3
+ import { StartingContentSkeleton } from '@/components/skeletons/StartingContentSkeleton'
4
+ import { StartingSkeleton } from '@/components/skeletons/StartingSkeleton'
5
+ import { Message } from '@/types'
6
+
7
+ type Args = {
8
+ latestMessage: Message | null
9
+ isRunActive: boolean
10
+ }
11
+
12
+ export const ProgressMessage = ({
13
+ latestMessage,
14
+ isRunActive,
15
+ }: Args) => {
16
+ if (!latestMessage) return null
17
+ if (!isRunActive) return null
18
+
19
+ if (latestMessage.role === 'user') {
20
+ return (
21
+ <StartingSkeleton />
22
+ )
23
+ }
24
+
25
+ return (
26
+ <MessagesGroupBase>
27
+ <Box pl="5" />
28
+ <StartingContentSkeleton />
29
+ </MessagesGroupBase>
30
+ )
31
+ }