@baseai/core
Version:
The Web AI Framework's core - BaseAI.dev
1 lines • 17.7 kB
Source Map (JSON)
{"version":3,"sources":["../../src/react/use-pipe.ts","../../src/helpers/stream.ts","../../src/utils/is-prod.ts"],"sourcesContent":["import React, {useCallback, useMemo, useRef, useState} from 'react';\nimport {Message, MessageRole} from 'types/pipes';\nimport {z} from 'zod';\nimport {getRunner, Runner} from '../helpers';\nimport {RunResponse} from '../pipes/pipes';\nimport {isProd} from '../utils/is-prod';\n\ninterface PipeRequestOptions {\n\theaders?: Record<string, string> | Headers;\n\tbody?: any;\n\tdata?: any;\n\tallowEmptySubmit?: boolean;\n}\n\ninterface UsePipeOptions {\n\tapiRoute?: string;\n\tonResponse?: (message: Message) => void;\n\tonFinish?: (messages: Message[]) => void;\n\tonConnect?: () => void;\n\tonError?: (error: Error) => void;\n\tthreadId?: string;\n\tinitialMessages?: Message[];\n\tstream?: boolean;\n}\n\nconst uuidSchema = z.string().uuid();\nconst externalThreadIdSchema = uuidSchema.optional();\n\nexport function usePipe({\n\tapiRoute = '/langbase/pipes/run-stream',\n\tonResponse,\n\tonFinish,\n\tonConnect,\n\tonError,\n\tthreadId: initialThreadId,\n\tinitialMessages = [],\n\tstream = true,\n}: UsePipeOptions = {}) {\n\tconst [messages, setMessages] = useState<Message[]>(initialMessages);\n\tconst [input, setInput] = useState('');\n\tconst [isLoading, setIsLoading] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst abortControllerRef = useRef<AbortController | null>(null);\n\tconst threadIdRef = useRef<string | undefined>(\n\t\tinitialThreadId || undefined,\n\t);\n\tconst messagesRef = useRef<Message[]>(initialMessages);\n\tconst isFirstRequestRef = useRef<boolean>(true);\n\n\tconst updateMessages = useCallback((newMessages: Message[]) => {\n\t\tmessagesRef.current = newMessages;\n\t\tsetMessages(newMessages);\n\t}, []);\n\n\tconst processStreamResponse = useCallback(\n\t\tasync (runner: Runner) => {\n\t\t\tlet assistantMessage: Message = {role: 'assistant', content: ''};\n\t\t\tupdateMessages([...messagesRef.current, assistantMessage]);\n\n\t\t\tfor await (const chunk of runner) {\n\t\t\t\tif (abortControllerRef.current?.signal.aborted) break;\n\n\t\t\t\tconst content = chunk.choices[0]?.delta?.content || '';\n\t\t\t\tassistantMessage.content += content;\n\n\t\t\t\tupdateMessages([\n\t\t\t\t\t...messagesRef.current.slice(0, -1),\n\t\t\t\t\t{...assistantMessage},\n\t\t\t\t]);\n\t\t\t\tonResponse?.({...assistantMessage});\n\t\t\t}\n\n\t\t\tonFinish?.(messagesRef.current);\n\t\t},\n\t\t[updateMessages, onResponse, onFinish],\n\t);\n\n\tconst processNonStreamResponse = useCallback(\n\t\t(result: RunResponse) => {\n\t\t\tconst assistantMessage: Message = {\n\t\t\t\trole: 'assistant',\n\t\t\t\tcontent: result.completion,\n\t\t\t};\n\t\t\tconst newMessages = [...messagesRef.current, assistantMessage];\n\t\t\tupdateMessages(newMessages);\n\t\t\tonResponse?.(assistantMessage);\n\t\t\tonFinish?.(newMessages);\n\t\t},\n\t\t[updateMessages, onResponse, onFinish],\n\t);\n\n\tconst setThreadId = useCallback((newThreadId: string | undefined) => {\n\t\tconst isValidThreadId =\n\t\t\texternalThreadIdSchema.safeParse(newThreadId).success;\n\n\t\tif (isValidThreadId) {\n\t\t\tthreadIdRef.current = newThreadId;\n\t\t} else {\n\t\t\tthrow new Error('Invalid thread ID');\n\t\t}\n\t}, []);\n\n\tconst getMessagesToSend = useCallback(\n\t\t(updatedMessages: Message[]): [Message[], boolean] => {\n\t\t\tconst isInitialRequest = isFirstRequestRef.current;\n\t\t\tisFirstRequestRef.current = false;\n\n\t\t\tif (!isProd()) {\n\t\t\t\t// In local environment, always send all messages and set lastMessageOnly to false\n\t\t\t\treturn [updatedMessages, false];\n\t\t\t}\n\n\t\t\tif (isInitialRequest) {\n\t\t\t\t// In production, for the initial request, send all messages\n\t\t\t\treturn [updatedMessages, false];\n\t\t\t} else {\n\t\t\t\t// In production, for subsequent requests, send only the last message if there are more than initial messages\n\t\t\t\tconst lastMessageOnly =\n\t\t\t\t\tupdatedMessages.length > initialMessages.length;\n\t\t\t\treturn [\n\t\t\t\t\tlastMessageOnly\n\t\t\t\t\t\t? [updatedMessages[updatedMessages.length - 1]]\n\t\t\t\t\t\t: updatedMessages,\n\t\t\t\t\tlastMessageOnly,\n\t\t\t\t];\n\t\t\t}\n\t\t},\n\t\t[initialMessages],\n\t);\n\n\tconst sendRequest = useCallback(\n\t\tasync (content: string | null, options: PipeRequestOptions = {}) => {\n\t\t\tabortControllerRef.current = new AbortController();\n\t\t\tconst {signal} = abortControllerRef.current;\n\n\t\t\ttry {\n\t\t\t\tsetIsLoading(true);\n\t\t\t\tsetError(null);\n\t\t\t\tonConnect?.();\n\n\t\t\t\tlet updatedMessages = messagesRef.current;\n\n\t\t\t\tconst hasContent = content && content.trim();\n\t\t\t\tif (hasContent) {\n\t\t\t\t\t// Add new user message only if content is not empty\n\t\t\t\t\tupdatedMessages = [\n\t\t\t\t\t\t...messagesRef.current,\n\t\t\t\t\t\t{role: 'user' as MessageRole, content},\n\t\t\t\t\t];\n\t\t\t\t}\n\n\t\t\t\tupdateMessages(updatedMessages);\n\n\t\t\t\tconst [messagesToSend, lastMessageOnly] =\n\t\t\t\t\tgetMessagesToSend(updatedMessages);\n\n\t\t\t\t// Ensure there's at least one message to send if not allowing empty submit\n\t\t\t\tif (messagesToSend.length === 0 && !options.allowEmptySubmit) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'At least one message or initial message is required',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst requestBody: any = {\n\t\t\t\t\tmessages: messagesToSend,\n\t\t\t\t\tstream,\n\t\t\t\t\tlastMessageOnly,\n\t\t\t\t\t...options.body,\n\t\t\t\t};\n\n\t\t\t\tif (\n\t\t\t\t\tthreadIdRef.current &&\n\t\t\t\t\tuuidSchema.safeParse(threadIdRef.current).success\n\t\t\t\t) {\n\t\t\t\t\trequestBody.threadId = threadIdRef.current;\n\t\t\t\t}\n\n\t\t\t\tconst response = await fetch(apiRoute, {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t...(options.headers || {}),\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify(requestBody),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\n\t\t\t\tif (!response.ok) await processErrorResponse(response);\n\n\t\t\t\tconst newThreadId = response.headers.get('lb-thread-id');\n\t\t\t\tif (newThreadId) threadIdRef.current = newThreadId;\n\n\t\t\t\tif (stream && response.body) {\n\t\t\t\t\tawait processStreamResponse(getRunner(response.body));\n\t\t\t\t} else {\n\t\t\t\t\tconst result: RunResponse = await response.json();\n\t\t\t\t\tprocessNonStreamResponse(result);\n\t\t\t\t}\n\t\t\t} catch (err: any) {\n\t\t\t\tif (err instanceof Error && err.name !== 'AbortError') {\n\t\t\t\t\tsetError(err);\n\t\t\t\t\tonError?.(err);\n\t\t\t\t} else if (err.name !== 'AbortError') {\n\t\t\t\t\tthrow new Error('Failed to send message');\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tsetIsLoading(false);\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tapiRoute,\n\t\t\tstream,\n\t\t\tprocessStreamResponse,\n\t\t\tprocessNonStreamResponse,\n\t\t\tupdateMessages,\n\t\t\tonConnect,\n\t\t\tonError,\n\t\t\tgetMessagesToSend,\n\t\t],\n\t);\n\n\tconst handleSubmit = useCallback(\n\t\t(\n\t\t\tevent?: {preventDefault?: () => void},\n\t\t\toptions: PipeRequestOptions = {},\n\t\t) => {\n\t\t\tevent?.preventDefault?.();\n\t\t\tconst currentInput = input.trim();\n\t\t\tsetInput('');\n\t\t\treturn sendRequest(currentInput, options);\n\t\t},\n\t\t[input, sendRequest],\n\t);\n\n\tconst handleInputChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n\t\t\tsetInput(e.target.value);\n\t\t},\n\t\t[],\n\t);\n\n\tconst sendMessage = useCallback(\n\t\tasync (\n\t\t\tcontent: string,\n\t\t\toptions: PipeRequestOptions = {},\n\t\t): Promise<void> => {\n\t\t\tawait sendRequest(content.trim(), options);\n\t\t},\n\t\t[sendRequest],\n\t);\n\n\tconst regenerate = useCallback(\n\t\tasync (options: PipeRequestOptions = {}): Promise<void> => {\n\t\t\tconst lastUserMessage = messagesRef.current.findLast(\n\t\t\t\tm => m.role === 'user',\n\t\t\t);\n\t\t\tif (!lastUserMessage) return;\n\t\t\tawait sendRequest(lastUserMessage.content, options);\n\t\t},\n\t\t[sendRequest],\n\t);\n\n\tconst stop = useCallback(() => {\n\t\tabortControllerRef.current?.abort();\n\t\tsetIsLoading(false);\n\t}, []);\n\n\tconst processErrorResponse = async (response: Response) => {\n\t\tconst res = await response.json();\n\t\tif (res.error.error) {\n\t\t\t// Throw error object if it exists\n\t\t\tthrow new Error(res.error.error.message);\n\t\t} else {\n\t\t\tthrow new Error('Failed to send message');\n\t\t}\n\t};\n\n\treturn useMemo(\n\t\t() => ({\n\t\t\tmessages,\n\t\t\tinput,\n\t\t\thandleInputChange,\n\t\t\thandleSubmit,\n\t\t\tisLoading,\n\t\t\terror,\n\t\t\tregenerate,\n\t\t\tstop,\n\t\t\tsetMessages: updateMessages,\n\t\t\tthreadId: threadIdRef.current,\n\t\t\tsendMessage,\n\t\t\tsetInput,\n\t\t\tsetThreadId,\n\t\t}),\n\t\t[\n\t\t\tmessages,\n\t\t\tinput,\n\t\t\thandleInputChange,\n\t\t\thandleSubmit,\n\t\t\tisLoading,\n\t\t\terror,\n\t\t\tregenerate,\n\t\t\tstop,\n\t\t\tupdateMessages,\n\t\t\tsendMessage,\n\t\t],\n\t);\n}\n","import {ChatCompletionStream} from 'openai/lib/ChatCompletionStream';\nimport {ChunkStream} from 'src/pipes';\nimport {Stream} from 'openai/streaming';\nimport {ToolCallResult} from 'types/pipes';\n\nexport interface Runner extends ChatCompletionStream<null> {}\n\n/**\n * Converts a ReadableStream into a Runner.\n *\n * @param readableStream - The ReadableStream to convert.\n * @returns The converted Runner.\n */\nexport const fromReadableStream = (readableStream: ReadableStream): Runner => {\n\treturn ChatCompletionStream.fromReadableStream(readableStream);\n};\n\n/**\n * Returns a runner for the given readable stream.\n *\n * @param readableStream - The readable stream to create a runner for.\n * @returns A runner for the given readable stream.\n */\nexport const getRunner = (readableStream: ReadableStream) => {\n\treturn fromReadableStream(readableStream);\n};\n\n/**\n * Retrieves the text part from a given ChunkStream.\n *\n * @param chunk - The ChunkStream object.\n * @returns The text content of the first choice's delta, or an empty string if it doesn't exist.\n */\nexport const getTextPart = (chunk: ChunkStream) => {\n\treturn chunk.choices[0]?.delta?.content || '';\n};\n\n/**\n * Handles the response stream from a given `Response` object.\n *\n * @param {Object} params - The parameters for handling the response stream.\n * @param {Response} params.response - The API response to handle.\n * @param {boolean} params.rawResponse - Optional flag to include raw response headers.\n *\n * @returns {Object} An object containing the processed stream, thread ID, and optionally raw response headers.\n * @returns {ReadableStream<any>} return.stream - The readable stream created from the response.\n * @returns {string | null} return.threadId - The thread ID extracted from the response headers.\n * @returns {Object} [return.rawResponse] - Optional raw response headers.\n * @returns {Record<string, string>} return.rawResponse.headers - The headers from the raw response.\n */\nexport function handleResponseStream({\n\tresponse,\n\trawResponse,\n}: {\n\tresponse: Response;\n\trawResponse?: boolean;\n}): {\n\tstream: any;\n\tthreadId: string | null;\n\trawResponse?: {\n\t\theaders: Record<string, string>;\n\t};\n} {\n\tconst controller = new AbortController();\n\tconst streamSSE = Stream.fromSSEResponse(response, controller);\n\tconst stream = streamSSE.toReadableStream();\n\n\tconst result: {\n\t\tstream: ReadableStream<any>;\n\t\tthreadId: string | null;\n\t\trawResponse?: {\n\t\t\theaders: Record<string, string>;\n\t\t};\n\t} = {\n\t\tstream,\n\t\tthreadId: response.headers.get('lb-thread-id'),\n\t};\n\tif (rawResponse) {\n\t\tresult.rawResponse = {\n\t\t\theaders: Object.fromEntries(response.headers.entries()),\n\t\t};\n\t}\n\treturn result;\n}\n\n/**\n * Retrieves tool calls from a given readable stream.\n *\n * @param stream - The readable stream from which to extract tool calls.\n * @returns A promise that resolves to an array of `ToolCall` objects.\n */\nexport async function getToolsFromStream(\n\tstream: ReadableStream<any>,\n): Promise<ToolCallResult[]> {\n\tlet run = getRunner(stream);\n\tconst {choices} = await run.finalChatCompletion();\n\treturn choices[0].message.tool_calls;\n}\n","const FORCE_PROD = false;\nconst TEST_PROD_LOCALLY = FORCE_PROD;\n\nexport function isProd() {\n\tif (TEST_PROD_LOCALLY) return true;\n\treturn process.env.NODE_ENV === 'production';\n}\n\nexport function isLocal() {\n\treturn process.env.NODE_ENV !== 'production';\n}\n\nexport function getApiUrl(prod?: boolean) {\n\tif (prod) return 'https://api.langbase.com';\n\telse return 'http://localhost:9000';\n\n\t// TODO: Make local port configurable.\n\t// return isProd() ? 'https://api.langbase.com' : 'http://localhost:9000';\n\t// return isProd() ? 'http://localhost:8787' : 'http://localhost:9000';\n}\n"],"mappings":"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","names":[]}