@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
@@ -0,0 +1,28 @@
1
+ import { forwardRef } from 'react'
2
+ import TextareaAutosize from 'react-textarea-autosize'
3
+
4
+ const UPSCALE_RATIO = 16 / 14
5
+
6
+ type Props = React.ComponentProps<typeof TextareaAutosize>
7
+
8
+ export const TextareaBase = forwardRef(function TextareaBase(props: Props, ref) {
9
+ return (
10
+ <TextareaAutosize
11
+ // @ts-ignore-next-line
12
+ ref={ref}
13
+ className="textarea-base"
14
+ style={{
15
+ resize: 'none',
16
+ fontSize: `${14 * UPSCALE_RATIO}px`,
17
+ lineHeight: `${24 * UPSCALE_RATIO}px`,
18
+ transform: `scale(${1 / UPSCALE_RATIO})`,
19
+ margin: `0 ${(-100 * UPSCALE_RATIO + 100) / 2}%`,
20
+ width: `${100 * UPSCALE_RATIO}%`,
21
+ maxWidth: `${100 * UPSCALE_RATIO}%`,
22
+ flexGrow: 1,
23
+ display: 'flex',
24
+ }}
25
+ {...props}
26
+ />
27
+ )
28
+ })
@@ -0,0 +1,17 @@
1
+ import {
2
+ Text,
3
+ } from '@radix-ui/themes'
4
+
5
+ type Args = {
6
+ children: React.ReactNode
7
+ }
8
+
9
+ export const ToolCallTitle = ({
10
+ children,
11
+ }: Args) => (
12
+ <Text
13
+ weight="regular"
14
+ >
15
+ {children}
16
+ </Text>
17
+ )
@@ -0,0 +1,34 @@
1
+ import { forwardRef } from 'react'
2
+ import {
3
+ Flex,
4
+ Button,
5
+ PopoverTrigger
6
+ } from '@radix-ui/themes'
7
+
8
+ type Args = {
9
+ children: React.ReactNode
10
+ }
11
+
12
+ export const ToolCallBase = forwardRef(function ToolCallBase({
13
+ children,
14
+ }: Args, ref) {
15
+ return (
16
+ <Flex
17
+ py="1"
18
+ ml="-2"
19
+ >
20
+ <PopoverTrigger>
21
+ <Button
22
+ size="1"
23
+ color="gold"
24
+ variant="outline"
25
+ style={{
26
+ boxShadow: 'none',
27
+ }}
28
+ >
29
+ {children}
30
+ </Button>
31
+ </PopoverTrigger>
32
+ </Flex>
33
+ )
34
+ })
@@ -0,0 +1,3 @@
1
+ import { createContext } from 'react'
2
+
3
+ export const AssistantNameContext = createContext('Assistant')
@@ -0,0 +1,14 @@
1
+ import { createContext } from 'react'
2
+ import {
3
+ Avatar,
4
+ } from '@radix-ui/themes'
5
+ import {
6
+ LightningBoltIcon,
7
+ } from '@radix-ui/react-icons'
8
+
9
+ export const AssistantAvatarContext = createContext(
10
+ <Avatar
11
+ fallback={<LightningBoltIcon />}
12
+ size="1"
13
+ />
14
+ )
@@ -0,0 +1,7 @@
1
+ import { createContext } from 'react'
2
+ import { components } from './lib/components'
3
+
4
+ export const MarkdownContext = createContext({
5
+ remarkPlugins: [] as any[],
6
+ components,
7
+ })
@@ -0,0 +1,13 @@
1
+ import {
2
+ Link as RadixLink,
3
+ } from '@radix-ui/themes'
4
+
5
+ type Args = JSX.IntrinsicElements['a']
6
+
7
+ export const Link = ({ children, href }: Args) => (
8
+ <RadixLink
9
+ href={href}
10
+ >
11
+ {children}
12
+ </RadixLink>
13
+ )
@@ -0,0 +1,13 @@
1
+ import {
2
+ Box,
3
+ } from '@radix-ui/themes'
4
+
5
+ export const ListItem = ({ children }: JSX.IntrinsicElements['li']) => (
6
+ <Box
7
+ pb="1"
8
+ >
9
+ <li>
10
+ {children}
11
+ </li>
12
+ </Box>
13
+ )
@@ -0,0 +1,16 @@
1
+ import {
2
+ Box,
3
+ } from '@radix-ui/themes'
4
+
5
+ export const OrderedList = ({ children }: JSX.IntrinsicElements['ul']) => (
6
+ <Box
7
+ pb="3"
8
+ asChild
9
+ >
10
+ <ol
11
+ className="list-inside"
12
+ >
13
+ {children}
14
+ </ol>
15
+ </Box>
16
+ )
@@ -0,0 +1,17 @@
1
+ import {
2
+ Box,
3
+ Text,
4
+ } from '@radix-ui/themes'
5
+
6
+ export const Paragraph = ({ children }: JSX.IntrinsicElements['p']) => (
7
+ <Box
8
+ pb="3"
9
+ >
10
+ <Text
11
+ size="3"
12
+ className="whitespace-pre-line break-words"
13
+ >
14
+ {children}
15
+ </Text>
16
+ </Box>
17
+ )
@@ -0,0 +1,9 @@
1
+ import {
2
+ Strong as RadixStrong,
3
+ } from '@radix-ui/themes'
4
+
5
+ export const Strong = ({ children }: JSX.IntrinsicElements['strong']) => (
6
+ <RadixStrong>
7
+ {children}
8
+ </RadixStrong>
9
+ )
@@ -0,0 +1,16 @@
1
+ import {
2
+ Box,
3
+ } from '@radix-ui/themes'
4
+
5
+ export const UnorderedList = ({ children }: JSX.IntrinsicElements['ul']) => (
6
+ <Box
7
+ pb="3"
8
+ asChild
9
+ >
10
+ <ul
11
+ className="list-inside"
12
+ >
13
+ {children}
14
+ </ul>
15
+ </Box>
16
+ )
@@ -0,0 +1,16 @@
1
+ import { Components } from 'react-markdown'
2
+ import { Paragraph } from './Paragraph'
3
+ import { Link } from './Link'
4
+ import { UnorderedList } from './UnorderedList'
5
+ import { OrderedList } from './OrderedList'
6
+ import { ListItem } from './ListItem'
7
+ import { Strong } from './Strong'
8
+
9
+ export const components: Components = {
10
+ p: Paragraph,
11
+ a: Link,
12
+ strong: Strong,
13
+ ul: UnorderedList,
14
+ ol: OrderedList,
15
+ li: ListItem,
16
+ }
@@ -0,0 +1,30 @@
1
+ import {
2
+ useMutation,
3
+ useQueryClient,
4
+ UseMutationOptions,
5
+ } from '@tanstack/react-query'
6
+ import { mutationOptions } from './lib/mutationOptions'
7
+ import { Run } from '@/types'
8
+
9
+ type Args = {
10
+ handleActionMutationOptions: UseMutationOptions<{ run: Run }>
11
+ }
12
+
13
+ export const useHandleAction = ({
14
+ handleActionMutationOptions,
15
+ }: Args) => {
16
+ const queryClient = useQueryClient()
17
+
18
+ // @ts-ignore-next-line
19
+ const mutationProps = useMutation({
20
+ ...mutationOptions({
21
+ queryClient,
22
+ }),
23
+ ...handleActionMutationOptions,
24
+ })
25
+
26
+ return {
27
+ ...mutationProps,
28
+ handleAction: mutationProps.mutate,
29
+ }
30
+ }
@@ -0,0 +1,14 @@
1
+ import { QueryClient } from '@tanstack/react-query'
2
+ // import { mutationFn } from './mutationFn'
3
+ import { onSettled } from './onSettled'
4
+
5
+ type Args = {
6
+ queryClient: QueryClient
7
+ }
8
+
9
+ export const mutationOptions = ({
10
+ queryClient,
11
+ }: Args) => ({
12
+ // mutationFn,
13
+ onSettled: onSettled({ queryClient }),
14
+ })
@@ -0,0 +1,39 @@
1
+ import { Run, Functions } from '@/types'
2
+ import pMap from 'p-map'
3
+ import { client } from '@/lib/ai'
4
+ import { toolOutput } from './toolOutput'
5
+
6
+ type Args = {
7
+ latestRun: Run
8
+ functions?: Functions
9
+ }
10
+
11
+ export type Response = {
12
+ run: Run
13
+ }
14
+
15
+ export const mutationFn = async ({
16
+ latestRun,
17
+ functions = {},
18
+ }: Args): Promise<Response> => {
19
+ if (!latestRun.required_action) {
20
+ throw new Error('No required_action for run ${latestRun.id} with status ${latestRun.status}')
21
+ }
22
+
23
+ console.log('handleActions', { latestRun })
24
+
25
+ const toolCalls = latestRun.required_action.submit_tool_outputs.tool_calls
26
+
27
+ const run = await client.beta.threads.runs.submitToolOutputs(
28
+ latestRun.thread_id,
29
+ latestRun.id,
30
+ {
31
+ tool_outputs: await pMap(toolCalls, (toolCall) => toolOutput({ toolCall, latestRun, functions })),
32
+ },
33
+ )
34
+
35
+ return {
36
+ // @ts-ignore-next-line
37
+ run,
38
+ }
39
+ }
@@ -0,0 +1,29 @@
1
+ import OpenAI from 'openai'
2
+ import { Functions } from '@/types'
3
+
4
+ type Args = {
5
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
6
+ latestRun: OpenAI.Beta.Threads.Runs.Run
7
+ functions: Functions
8
+ }
9
+
10
+ export const toolOutput = async ({
11
+ toolCall,
12
+ latestRun,
13
+ functions,
14
+ }: Args) => {
15
+ const fn = functions[toolCall.function.name]
16
+
17
+ if (!fn) {
18
+ console.log({ toolCall })
19
+ throw new Error(`No function for ${toolCall.function.name}`)
20
+ }
21
+
22
+ return {
23
+ tool_call_id: toolCall.id,
24
+ output: await fn({
25
+ toolCall,
26
+ latestRun,
27
+ }),
28
+ }
29
+ }
@@ -0,0 +1,22 @@
1
+ import { queryKey as messagesQueryKey } from '@/hooks/messages/useMessages/lib/queryOptions/queryKey'
2
+ import { queryKey as runsQueryKey } from '@/hooks/runs/useRuns/lib/queryOptions/queryKey'
3
+ import { Response } from './mutationFn'
4
+
5
+ type Args = {
6
+ queryClient: any
7
+ }
8
+
9
+ export const onSettled = ({
10
+ queryClient,
11
+ }: Args) => (response: Response | undefined) => {
12
+ if (!response) {
13
+ throw new Error('useHandleAction onSettled: response is undefined')
14
+ }
15
+
16
+ queryClient.invalidateQueries({
17
+ queryKey: messagesQueryKey(),
18
+ })
19
+ queryClient.invalidateQueries({
20
+ queryKey: runsQueryKey(),
21
+ })
22
+ }
@@ -0,0 +1,43 @@
1
+ import {
2
+ UseInfiniteQueryOptions,
3
+ InfiniteData,
4
+ UseMutationOptions,
5
+ } from '@tanstack/react-query'
6
+ import { useEffect } from 'react'
7
+ import { useLatestRun } from '@/hooks/runs/useLatestRun'
8
+ import { useHandleAction } from '@/hooks/actions/useHandleAction'
9
+ import { RunsPage, Run } from '@/types'
10
+
11
+ type Args = {
12
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
13
+ handleActionMutationOptions: UseMutationOptions<{ run: Run }>
14
+ }
15
+
16
+ export const useManageActions = ({
17
+ runsQueryOptions,
18
+ handleActionMutationOptions,
19
+ }: Args) => {
20
+ const latestRunProps = useLatestRun({
21
+ runsQueryOptions,
22
+ })
23
+
24
+ const handleActionProps = useHandleAction({
25
+ handleActionMutationOptions,
26
+ })
27
+
28
+ useEffect(() => {
29
+ if (handleActionProps.isPending) return
30
+ if (latestRunProps.isFetching) return
31
+ if (!latestRunProps.latestRun) return
32
+ if (latestRunProps.latestRun.status !== 'requires_action') return
33
+
34
+ console.log('requires action', {
35
+ latestRunProps,
36
+ })
37
+
38
+ // @ts-ignore-next-line
39
+ handleActionProps.handleAction({ latestRun: latestRunProps.latestRun })
40
+ }, [handleActionProps, latestRunProps])
41
+
42
+ return null
43
+ }
@@ -0,0 +1,18 @@
1
+ import { useMemo } from 'react'
2
+ import { messageGroups as getMessageGroups } from './lib/messageGroups'
3
+ import { Message } from '@/types'
4
+
5
+ type Args = {
6
+ messages: Message[]
7
+ }
8
+
9
+ export const useMessageGroups = ({
10
+ messages,
11
+ }: Args) => (
12
+ useMemo(
13
+ () => ({
14
+ messageGroups: getMessageGroups({ messages }),
15
+ }),
16
+ [messages]
17
+ )
18
+ )
@@ -0,0 +1,37 @@
1
+ import _ from 'lodash'
2
+ import { last } from 'radash'
3
+ import { Message, MessageGroup } from '@/types'
4
+ import { order } from '@/lib/messages/order'
5
+ import { newGroup } from './newGroup'
6
+
7
+ type Args = {
8
+ messages: Message[]
9
+ }
10
+
11
+ export const messageGroups = ({
12
+ messages,
13
+ }: Args) =>
14
+ _.reduce(
15
+ order({ messages }),
16
+ (groups: MessageGroup[], message: Message) => {
17
+ const group = last(groups)
18
+
19
+ if (!group) return newGroup({ groups, message })
20
+
21
+ if (group.role !== message.role) {
22
+ return newGroup({
23
+ groups,
24
+ message,
25
+ })
26
+ }
27
+
28
+ return [
29
+ ..._.dropRight(groups),
30
+ {
31
+ ...group,
32
+ messages: [...group.messages, message],
33
+ },
34
+ ]
35
+ },
36
+ []
37
+ )
@@ -0,0 +1,14 @@
1
+ import { Message, MessageGroup } from '@/types'
2
+ import { newGroupItem } from './newGroupItem'
3
+
4
+ type Args = {
5
+ groups: MessageGroup[]
6
+ message: Message
7
+ }
8
+
9
+ export const newGroup = ({ groups, message }: Args) => [
10
+ ...groups,
11
+ newGroupItem({
12
+ message,
13
+ }),
14
+ ]
@@ -0,0 +1,12 @@
1
+ import { Message } from '@/types'
2
+
3
+ type Args = {
4
+ message: Message
5
+ }
6
+
7
+ export const newGroupItem = ({ message }: Args) => ({
8
+ id: message.id,
9
+ role: message.role,
10
+ createdAt: message.created_at,
11
+ messages: [message],
12
+ })
@@ -0,0 +1,30 @@
1
+ import {
2
+ useMutation,
3
+ useQueryClient,
4
+ UseMutationOptions,
5
+ } from '@tanstack/react-query'
6
+ import { mutationOptions } from './lib/mutationOptions'
7
+ import { Message } from '@/types'
8
+
9
+ type Args = {
10
+ createMessageMutationOptions: UseMutationOptions<{ message: Message }>
11
+ }
12
+
13
+ export const useCreateMessage = ({
14
+ createMessageMutationOptions,
15
+ }: Args) => {
16
+ const queryClient = useQueryClient()
17
+
18
+ // @ts-ignore-next-line
19
+ const mutationProps = useMutation({
20
+ ...mutationOptions({
21
+ queryClient,
22
+ }),
23
+ ...createMessageMutationOptions,
24
+ })
25
+
26
+ return {
27
+ ...mutationProps,
28
+ createMessage: mutationProps.mutateAsync,
29
+ }
30
+ }
@@ -0,0 +1,24 @@
1
+ import { QueryClient } from '@tanstack/react-query'
2
+ // import { mutationFn } from './mutationFn'
3
+ import { onMutate } from './onMutate'
4
+ import { onError } from './onError'
5
+ import { onSettled } from './onSettled'
6
+
7
+ type Args = {
8
+ queryClient: QueryClient
9
+ }
10
+
11
+ export const mutationOptions = ({
12
+ queryClient,
13
+ }: Args) => ({
14
+ // mutationFn,
15
+ onMutate: onMutate({
16
+ queryClient,
17
+ }),
18
+ onError: onError({
19
+ queryClient,
20
+ }),
21
+ onSettled: onSettled({
22
+ queryClient,
23
+ }),
24
+ })
@@ -0,0 +1,25 @@
1
+ import { client } from '@/lib/ai'
2
+ import { Message } from '@/types'
3
+ import { extendMessage } from '@/lib/messages/extendMessage'
4
+
5
+ export type Args = {
6
+ content: string
7
+ threadId: string
8
+ }
9
+
10
+ export type Response = {
11
+ message: Message
12
+ }
13
+
14
+ export const mutationFn = async ({ content, threadId }: Args): Promise<Response> => {
15
+ const message = await client.beta.threads.messages.create(threadId, {
16
+ content: content,
17
+ role: 'user',
18
+ })
19
+
20
+ return {
21
+ message: await extendMessage({
22
+ message,
23
+ }),
24
+ }
25
+ }
@@ -0,0 +1,27 @@
1
+ import { queryKey as messagesQueryKey } from '@/hooks/messages/useMessages/lib/queryOptions/queryKey'
2
+ import { Args as NewMessageArgs } from './mutationFn'
3
+
4
+ type Args = {
5
+ queryClient: any
6
+ }
7
+
8
+ type Context = {
9
+ prevMessages: any
10
+ } | undefined
11
+
12
+ export const onError = ({
13
+ queryClient,
14
+ }: Args) => async (
15
+ _error: any,
16
+ newMessage: NewMessageArgs,
17
+ context: Context
18
+ ) => {
19
+ if (!context) {
20
+ return
21
+ }
22
+
23
+ queryClient.setQueryData(
24
+ messagesQueryKey(),
25
+ context.prevMessages,
26
+ )
27
+ }
@@ -0,0 +1,62 @@
1
+ import OpenAI from 'openai'
2
+ import { optimisticId } from '@/lib/optimistic/optimisticId'
3
+ import { Args as NewMessageArgs } from '../mutationFn'
4
+
5
+ type Args = {
6
+ newMessage: NewMessageArgs
7
+ }
8
+
9
+ export const data = ({
10
+ newMessage,
11
+ }: Args) => (prevData: any) => {
12
+ const message = {
13
+ id: optimisticId(),
14
+ role: 'user' as OpenAI.Beta.Threads.Messages.ThreadMessage['role'],
15
+ created_at: +new Date(),
16
+ object: 'thread.message' as OpenAI.Beta.Threads.Messages.ThreadMessage['object'],
17
+ content: [
18
+ {
19
+ type: 'text',
20
+ text: {
21
+ annotations: [],
22
+ value: newMessage.content,
23
+ },
24
+ } as OpenAI.Beta.Threads.Messages.MessageContentText,
25
+ ],
26
+ run_id: null,
27
+ assistant_id: null,
28
+ thread_id: null,
29
+ file_ids: [],
30
+ metadata: {},
31
+ runSteps: [],
32
+ }
33
+
34
+ if (!prevData) {
35
+ return {
36
+ pageParams: [],
37
+ pages: [
38
+ {
39
+ data: [message],
40
+ hasNextPage: false,
41
+ lastId: message.id,
42
+ },
43
+ ],
44
+ }
45
+ }
46
+
47
+ const [latestPage, ...pagesRest] = prevData.pages
48
+
49
+ return {
50
+ ...prevData,
51
+ pages: [
52
+ {
53
+ ...latestPage,
54
+ data: [
55
+ message,
56
+ ...latestPage.data,
57
+ ],
58
+ },
59
+ ...pagesRest,
60
+ ],
61
+ }
62
+ }