@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,25 @@
1
+ import { queryKey as messagesQueryKey } from '@/hooks/messages/useMessages/lib/queryOptions/queryKey'
2
+ import { Args as NewMessageArgs } from '../mutationFn'
3
+ import { data } from './data'
4
+
5
+ type Args = {
6
+ queryClient: any
7
+ }
8
+
9
+ export const onMutate = ({
10
+ queryClient,
11
+ }: Args) => async (newMessage: NewMessageArgs) => {
12
+ await queryClient.cancelQueries(messagesQueryKey())
13
+
14
+ const prevMessages = queryClient.getQueryData(messagesQueryKey())
15
+
16
+ queryClient.setQueryData(
17
+ messagesQueryKey(),
18
+ data({ newMessage })
19
+ )
20
+
21
+ return {
22
+ prevMessages,
23
+ newMessage,
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ import { queryKey as messagesQueryKey } from '@/hooks/messages/useMessages/lib/queryOptions/queryKey'
2
+ import { Response } from './mutationFn'
3
+
4
+ type Args = {
5
+ queryClient: any
6
+ }
7
+
8
+ export const onSettled = ({
9
+ queryClient,
10
+ }: Args) => async (response: Response | undefined) => {
11
+ if (!response) return
12
+
13
+ await queryClient.invalidateQueries({
14
+ queryKey: messagesQueryKey(),
15
+ })
16
+ }
@@ -0,0 +1,48 @@
1
+ import { queryKey as messagesQueryKey } from '@/hooks/messages/useMessages/lib/queryOptions/queryKey'
2
+ import { Response } from './mutationFn'
3
+
4
+ type Args = {
5
+ queryClient: any
6
+ passedOnSuccess?: () => void
7
+ }
8
+
9
+ export const onSuccess = ({
10
+ queryClient,
11
+ passedOnSuccess,
12
+ }: Args) => (response: Response) => {
13
+ passedOnSuccess?.()
14
+
15
+ queryClient.setQueryData(
16
+ messagesQueryKey(),
17
+ (prevData: any) => {
18
+ if (!prevData) {
19
+ return {
20
+ pageParams: [],
21
+ pages: [
22
+ {
23
+ data: [response.message],
24
+ hasNextPage: false,
25
+ lastId: response.message.id,
26
+ },
27
+ ],
28
+ }
29
+ }
30
+
31
+ const [latestPage, ...pagesRest] = prevData.pages
32
+
33
+ return {
34
+ ...prevData,
35
+ pages: [
36
+ {
37
+ ...latestPage,
38
+ data: [
39
+ response.message,
40
+ ...latestPage.data,
41
+ ],
42
+ },
43
+ ...pagesRest,
44
+ ],
45
+ }
46
+ }
47
+ )
48
+ }
@@ -0,0 +1,20 @@
1
+ import {
2
+ UseInfiniteQueryOptions,
3
+ InfiniteData,
4
+ } from '@tanstack/react-query'
5
+ import { useMemo } from 'react'
6
+ import { useMessages } from '@/hooks/messages/useMessages'
7
+ import { MessagesPage } from '@/types'
8
+
9
+ type Args = {
10
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
11
+ }
12
+
13
+ export const useLatestMessage = (args: Args) => {
14
+ const props = useMessages(args)
15
+
16
+ return useMemo(() => ({
17
+ ...props,
18
+ latestMessage: props.messages[0] || null,
19
+ }), [props])
20
+ }
@@ -0,0 +1,41 @@
1
+ import { useMemo } from 'react'
2
+ import {
3
+ useInfiniteQuery,
4
+ InfiniteData,
5
+ UseInfiniteQueryOptions,
6
+ } from '@tanstack/react-query'
7
+ import { Message, MessagesPage } from '@/types'
8
+ import { queryOptions as defaultQueryOptions } from './lib/queryOptions'
9
+
10
+ type Args = {
11
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
12
+ }
13
+
14
+ const messages = ({
15
+ props,
16
+ }: {
17
+ props: {
18
+ data: InfiniteData<MessagesPage> | undefined
19
+ },
20
+ }) => {
21
+ if (!props.data) return []
22
+
23
+ return props.data.pages.reduce<Message[]>((acc, page) => (
24
+ acc.concat(page.data)
25
+ ), [])
26
+ }
27
+
28
+
29
+ export const useMessages = ({
30
+ messagesQueryOptions,
31
+ }: Args) => {
32
+ const props = useInfiniteQuery({
33
+ ...defaultQueryOptions,
34
+ ...messagesQueryOptions,
35
+ })
36
+
37
+ return useMemo(() => ({
38
+ ...props,
39
+ messages: messages({ props }),
40
+ }), [props])
41
+ }
@@ -0,0 +1,20 @@
1
+ import { MessagesPage } from '@/types'
2
+ // import { queryFn } from './queryFn'
3
+ import { queryKey } from './queryKey'
4
+
5
+ export const queryOptions = {
6
+ queryKey: queryKey(),
7
+ // queryFn: ({
8
+ // pageParam,
9
+ // }: { pageParam?: string }) => (
10
+ // queryFn({
11
+ // ...(pageParam ? { cursor: pageParam } : {}),
12
+ // })
13
+ // ),
14
+ initialPageParam: undefined,
15
+ getNextPageParam: (lastPage: MessagesPage) => {
16
+ if (!lastPage.hasNextPage) return null
17
+
18
+ return lastPage.lastId
19
+ },
20
+ }
@@ -0,0 +1,32 @@
1
+ import OpenAI from 'openai'
2
+ import pMap from 'p-map'
3
+ import { extendMessage } from '@/lib/messages/extendMessage'
4
+ import { runMessages } from './runMessages'
5
+
6
+ export const data = async ({
7
+ messagesResponse,
8
+ cursor,
9
+ threadId,
10
+ }: {
11
+ messagesResponse: OpenAI.CursorPage<OpenAI.Beta.Threads.Messages.ThreadMessage>
12
+ cursor?: string
13
+ threadId: string
14
+ }) => {
15
+ const messages = await pMap(messagesResponse.data, (message) => (
16
+ extendMessage({
17
+ message,
18
+ })
19
+ ))
20
+
21
+ if (cursor) {
22
+ return messages
23
+ }
24
+
25
+ return [
26
+ ...await runMessages({
27
+ messages,
28
+ threadId,
29
+ }),
30
+ ...messages,
31
+ ]
32
+ }
@@ -0,0 +1,15 @@
1
+ import { client } from '@/lib/ai'
2
+
3
+ type Args = {
4
+ threadId: string
5
+ }
6
+
7
+ export const getLatestRun = async ({
8
+ threadId,
9
+ }: Args) => {
10
+ const runsResponse = await client.beta.threads.runs.list(threadId, {
11
+ limit: 1,
12
+ })
13
+
14
+ return runsResponse.data[0]
15
+ }
@@ -0,0 +1,44 @@
1
+ import OpenAI from 'openai'
2
+ import { Message } from '@/types'
3
+ import { getLatestRun } from './getLatestRun'
4
+ import { extendMessage } from '@/lib/messages/extendMessage'
5
+ import { optimisticId } from '@/lib/optimistic/optimisticId'
6
+
7
+ type Args = {
8
+ messages: Message[]
9
+ threadId: string
10
+ }
11
+
12
+ export const runMessages = async ({
13
+ messages,
14
+ threadId,
15
+ }: Args) => {
16
+ const latestRun = await getLatestRun({ threadId })
17
+
18
+ if (!latestRun) {
19
+ return []
20
+ }
21
+
22
+ const messageFromLatestRun = messages.find(m => m.run_id === latestRun.id)
23
+
24
+ if (messageFromLatestRun) {
25
+ return []
26
+ }
27
+
28
+ return [
29
+ await extendMessage({
30
+ message: {
31
+ id: optimisticId(),
32
+ role: 'assistant' as OpenAI.Beta.Threads.Messages.ThreadMessage['role'],
33
+ created_at: +new Date(),
34
+ object: 'thread.message' as OpenAI.Beta.Threads.Messages.ThreadMessage['object'],
35
+ content: [],
36
+ run_id: latestRun.id,
37
+ assistant_id: latestRun.assistant_id,
38
+ thread_id: latestRun.thread_id,
39
+ file_ids: [],
40
+ metadata: {},
41
+ },
42
+ }),
43
+ ]
44
+ }
@@ -0,0 +1,12 @@
1
+ import OpenAI from 'openai'
2
+ import { messagesLimit } from './messagesLimit'
3
+
4
+ export const hasNextPage = ({
5
+ messagesResponse,
6
+ }: {
7
+ messagesResponse: OpenAI.CursorPage<OpenAI.Beta.Threads.Messages.ThreadMessage>
8
+ }) => {
9
+ if (messagesResponse.data.length < messagesLimit) return false
10
+
11
+ return messagesResponse.hasNextPage()
12
+ }
@@ -0,0 +1,32 @@
1
+ import _ from 'lodash'
2
+ import { client } from '@/lib/ai'
3
+ import { MessagesPage } from '@/types'
4
+ import { data } from './data'
5
+ import { messagesLimit } from './messagesLimit'
6
+ import { hasNextPage } from './hasNextPage'
7
+
8
+ type Args = {
9
+ threadId: string
10
+ cursor?: string
11
+ }
12
+
13
+ export const queryFn = async ({
14
+ threadId,
15
+ cursor,
16
+ }: Args): Promise<MessagesPage> => {
17
+ const messagesResponse = await client.beta.threads.messages.list(threadId, {
18
+ ...(cursor ? { after: cursor } : {}),
19
+ limit: messagesLimit,
20
+ })
21
+
22
+ return {
23
+ data: await data({
24
+ messagesResponse,
25
+ cursor,
26
+ threadId,
27
+ }),
28
+ hasNextPage: hasNextPage({ messagesResponse }),
29
+ // @ts-ignore-next-line
30
+ lastId: messagesResponse.body.last_id,
31
+ }
32
+ }
@@ -0,0 +1 @@
1
+ export const messagesLimit = 10
@@ -0,0 +1,3 @@
1
+ export const queryKey = () => (
2
+ ['messages']
3
+ )
@@ -0,0 +1,42 @@
1
+ import { useRef } from 'react'
2
+ import { useInView } from 'react-intersection-observer'
3
+ import { useThrottledEffect } from '@/hooks/misc/useThrottledEffect'
4
+
5
+ type Args = {
6
+ isFetchingNextPage: boolean
7
+ hasNextPage: boolean
8
+ fetchNextPage: () => void
9
+ }
10
+
11
+ export const useInfiniteScroll = ({
12
+ isFetchingNextPage,
13
+ hasNextPage,
14
+ fetchNextPage,
15
+ }: Args) => {
16
+ const containerRef = useRef(null)
17
+
18
+ const { ref: loaderRef, inView } = useInView({
19
+ root: containerRef.current,
20
+ rootMargin: '0px',
21
+ threshold: 0.1,
22
+ })
23
+
24
+ useThrottledEffect(
25
+ () => {
26
+ if (isFetchingNextPage) return
27
+ if (!inView) return
28
+ if (!hasNextPage) return
29
+
30
+ console.log('Fetching next page')
31
+ fetchNextPage()
32
+ },
33
+ 500,
34
+ [inView, isFetchingNextPage, hasNextPage, fetchNextPage]
35
+ )
36
+
37
+ return {
38
+ containerRef,
39
+ loaderRef,
40
+ inView,
41
+ }
42
+ }
@@ -0,0 +1,19 @@
1
+ import _ from 'lodash'
2
+ import { useRef, useEffect, useCallback } from 'react'
3
+
4
+ export const useThrottledEffect = (cb: Function, delay: number, additionalDeps: any[]) => {
5
+ const cbRef = useRef(cb)
6
+
7
+ const throttledCb = useCallback(
8
+ _.throttle((...args: any[]) => cbRef.current(...args), delay, {
9
+ leading: true,
10
+ trailing: true,
11
+ }),
12
+ [delay]
13
+ )
14
+ useEffect(() => {
15
+ cbRef.current = cb
16
+ })
17
+ // set additionalDeps to execute effect, when other values change (not only on delay change)
18
+ useEffect(throttledCb, [throttledCb, ...additionalDeps])
19
+ }
@@ -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
+ createRunMutationOptions: UseMutationOptions<{ run: Run }>
11
+ }
12
+
13
+ export const useCreateRun = ({
14
+ createRunMutationOptions,
15
+ }: Args) => {
16
+ const queryClient = useQueryClient()
17
+
18
+ // @ts-ignore-next-line
19
+ const mutationProps = useMutation({
20
+ ...mutationOptions({
21
+ queryClient,
22
+ }),
23
+ ...createRunMutationOptions,
24
+ })
25
+
26
+ return {
27
+ ...mutationProps,
28
+ createRun: mutationProps.mutate,
29
+ }
30
+ }
@@ -0,0 +1,16 @@
1
+ import { QueryClient } from '@tanstack/react-query'
2
+ // import { mutationFn } from './mutationFn'
3
+ import { onSuccess } from './onSuccess'
4
+ import { onSettled } from './onSettled'
5
+
6
+ type Args = {
7
+ queryClient: QueryClient
8
+ }
9
+
10
+ export const mutationOptions = ({
11
+ queryClient,
12
+ }: Args) => ({
13
+ // mutationFn,
14
+ onSuccess: onSuccess({ queryClient }),
15
+ onSettled: onSettled({ queryClient }),
16
+ })
@@ -0,0 +1,30 @@
1
+ import { Run } from '@/types'
2
+ import { client } from '@/lib/ai'
3
+
4
+ type Args = {
5
+ threadId: string
6
+ assistantId: string
7
+ }
8
+
9
+ export type Response = {
10
+ run: Run
11
+ }
12
+
13
+ export const mutationFn = async ({
14
+ threadId,
15
+ assistantId,
16
+ }: Args): Promise<Response> => {
17
+ const run = await client.beta.threads.runs.create(threadId, {
18
+ assistant_id: assistantId,
19
+ // model: 'gpt-3.5-turbo-1106',
20
+ })
21
+
22
+ return {
23
+ // @ts-ignore-next-line
24
+ run,
25
+ }
26
+ // ...run,
27
+ // assistantConversationId,
28
+ // },
29
+ // }
30
+ }
@@ -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('useCreateRun onSettled: response is undefined')
14
+ }
15
+
16
+ queryClient.invalidateQueries({
17
+ queryKey: messagesQueryKey(),
18
+ })
19
+ queryClient.invalidateQueries({
20
+ queryKey: runsQueryKey(),
21
+ })
22
+ }
@@ -0,0 +1,44 @@
1
+ import { queryKey as runsQueryKey } from '@/hooks/runs/useRuns/lib/queryOptions/queryKey'
2
+ import { Response } from './mutationFn'
3
+
4
+ type Args = {
5
+ queryClient: any
6
+ }
7
+
8
+ export const onSuccess = ({
9
+ queryClient,
10
+ }: Args) => (response: Response) => (
11
+ queryClient.setQueryData(
12
+ runsQueryKey(),
13
+ (prevData: any) => {
14
+ if (!prevData) {
15
+ return {
16
+ pageParams: [],
17
+ pages: [
18
+ {
19
+ data: [response.run],
20
+ hasNextPage: false,
21
+ lastId: response.run.id,
22
+ },
23
+ ],
24
+ }
25
+ }
26
+
27
+ const [latestPage, ...pagesRest] = prevData.pages
28
+
29
+ return {
30
+ ...prevData,
31
+ pages: [
32
+ {
33
+ ...latestPage,
34
+ data: [
35
+ response.run,
36
+ ...latestPage.data,
37
+ ],
38
+ },
39
+ ...pagesRest,
40
+ ],
41
+ }
42
+ }
43
+ )
44
+ )
@@ -0,0 +1,65 @@
1
+ import {
2
+ UseInfiniteQueryOptions,
3
+ InfiniteData,
4
+ } from '@tanstack/react-query'
5
+ import { useMemo } from 'react'
6
+ import { useIsMutating } from '@tanstack/react-query'
7
+ import { useLatestRun } from '@/hooks/runs/useLatestRun'
8
+ import { useLatestMessage } from '@/hooks/messages/useLatestMessage'
9
+ import { isRunEditingMessage } from '@/lib/runs/isRunEditingMessage'
10
+ import { MessagesPage, RunsPage } from '@/types'
11
+
12
+ type Args = {
13
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
14
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
15
+ }
16
+
17
+ const statuses = [
18
+ 'queued',
19
+ // 'completed',
20
+ 'in_progress',
21
+ 'cancelling',
22
+ 'requires_action',
23
+ ]
24
+
25
+ const isRunActive = ({
26
+ latestRunProps,
27
+ latestMessageProps,
28
+ isMutating,
29
+ }: {
30
+ latestRunProps: ReturnType<typeof useLatestRun>,
31
+ latestMessageProps: ReturnType<typeof useLatestMessage>,
32
+ isMutating: number,
33
+ }) => {
34
+ // @ts-ignore-next-line
35
+ if (latestMessageProps.latestMessage?.metadata?.isBlocking) return false
36
+ if (isMutating > 0) return true
37
+ if (!latestRunProps.latestRun) return false
38
+ if (statuses.includes(latestRunProps.latestRun.status)) return true
39
+
40
+ return isRunEditingMessage({ message: latestMessageProps.latestMessage })
41
+ }
42
+
43
+ export const useIsRunActive = ({
44
+ messagesQueryOptions,
45
+ runsQueryOptions,
46
+ }: Args) => {
47
+ const latestRunProps = useLatestRun({
48
+ runsQueryOptions,
49
+ })
50
+
51
+ const latestMessageProps = useLatestMessage({
52
+ messagesQueryOptions,
53
+ })
54
+
55
+ const isMutating = useIsMutating()
56
+
57
+ return useMemo(() => ({
58
+ ...latestRunProps,
59
+ isRunActive: isRunActive({
60
+ latestRunProps,
61
+ latestMessageProps,
62
+ isMutating,
63
+ }),
64
+ }), [latestRunProps, latestMessageProps, isMutating])
65
+ }
@@ -0,0 +1,20 @@
1
+ import {
2
+ UseInfiniteQueryOptions,
3
+ InfiniteData,
4
+ } from '@tanstack/react-query'
5
+ import { useMemo } from 'react'
6
+ import { useRuns } from '@/hooks/runs/useRuns'
7
+ import { RunsPage } from '@/types'
8
+
9
+ type Args = {
10
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
11
+ }
12
+
13
+ export const useLatestRun = (args: Args) => {
14
+ const props = useRuns(args)
15
+
16
+ return useMemo(() => ({
17
+ ...props,
18
+ latestRun: props.runs[0],
19
+ }), [props])
20
+ }
@@ -0,0 +1,55 @@
1
+ import {
2
+ UseInfiniteQueryOptions,
3
+ UseMutationOptions,
4
+ InfiniteData,
5
+ } from '@tanstack/react-query'
6
+ import { useEffect } from 'react'
7
+ import { useLatestMessage } from '@/hooks/messages/useLatestMessage'
8
+ import { useLatestRun } from '@/hooks/runs/useLatestRun'
9
+ import { useCreateRun } from '@/hooks/runs/useCreateRun'
10
+ import { isOptimistic } from '@/lib/optimistic/isOptimistic'
11
+ import { MessagesPage, RunsPage, Run } from '@/types'
12
+
13
+ type Args = {
14
+ messagesQueryOptions: UseInfiniteQueryOptions<InfiniteData<MessagesPage>>
15
+ runsQueryOptions: UseInfiniteQueryOptions<InfiniteData<RunsPage>>
16
+ createRunMutationOptions: UseMutationOptions<{ run: Run }>
17
+ }
18
+
19
+ export const useManageRuns = ({
20
+ messagesQueryOptions,
21
+ runsQueryOptions,
22
+ createRunMutationOptions,
23
+ }: Args) => {
24
+ const latestRunProps = useLatestRun({
25
+ runsQueryOptions,
26
+ })
27
+
28
+ const latestMessageProps = useLatestMessage({
29
+ messagesQueryOptions,
30
+ })
31
+
32
+ const createRunProps = useCreateRun({
33
+ createRunMutationOptions,
34
+ })
35
+
36
+ useEffect(() => {
37
+ if (createRunProps.isPending) return
38
+ if (latestRunProps.isFetching) return
39
+ if (latestMessageProps.isFetching) return
40
+
41
+ if (!latestMessageProps.latestMessage) return
42
+ if (latestMessageProps.latestMessage.role !== 'user') return
43
+ if (isOptimistic({ id: latestMessageProps.latestMessage.id })) return
44
+
45
+ if (!latestRunProps.latestRun || (latestMessageProps.latestMessage.created_at > latestRunProps.latestRun.created_at)) {
46
+ createRunProps.createRun()
47
+ }
48
+ }, [
49
+ createRunProps,
50
+ latestRunProps,
51
+ latestMessageProps,
52
+ ])
53
+
54
+ return null
55
+ }