173
apps/builder/src/components/TagsInput.tsx
Normal file
173
apps/builder/src/components/TagsInput.tsx
Normal file
@ -0,0 +1,173 @@
|
||||
import {
|
||||
HStack,
|
||||
IconButton,
|
||||
Wrap,
|
||||
Text,
|
||||
WrapItem,
|
||||
Input,
|
||||
} from '@chakra-ui/react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { CloseIcon } from './icons'
|
||||
import { colors } from '@/lib/theme'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { convertStrToList } from '@typebot.io/lib/convertStrToList'
|
||||
import { isEmpty } from '@typebot.io/lib/utils'
|
||||
|
||||
type Props = {
|
||||
items?: string[]
|
||||
placeholder?: string
|
||||
onChange: (value: string[]) => void
|
||||
}
|
||||
export const TagsInput = ({ items, placeholder, onChange }: Props) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
const [focusedTagIndex, setFocusedTagIndex] = useState<number>()
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
e.preventDefault()
|
||||
setFocusedTagIndex(undefined)
|
||||
setInputValue(e.target.value)
|
||||
if (e.target.value.length - inputValue.length > 0) {
|
||||
const values = convertStrToList(e.target.value)
|
||||
if (values.length > 1) {
|
||||
onChange([...(items ?? []), ...convertStrToList(e.target.value)])
|
||||
setInputValue('')
|
||||
}
|
||||
}
|
||||
}
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (!items) return
|
||||
|
||||
if (e.key === 'Backspace') {
|
||||
if (focusedTagIndex !== undefined) {
|
||||
if (focusedTagIndex === items.length - 1) {
|
||||
setFocusedTagIndex((idx) => idx! - 1)
|
||||
}
|
||||
removeItem(focusedTagIndex)
|
||||
return
|
||||
}
|
||||
if (inputValue === '' && focusedTagIndex === undefined) {
|
||||
setFocusedTagIndex(items?.length - 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (e.key === 'ArrowLeft') {
|
||||
if (focusedTagIndex !== undefined) {
|
||||
if (focusedTagIndex === 0) return
|
||||
setFocusedTagIndex(focusedTagIndex - 1)
|
||||
return
|
||||
}
|
||||
if (inputRef.current?.selectionStart === 0 && items) {
|
||||
setFocusedTagIndex(items.length - 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (e.key === 'ArrowRight' && focusedTagIndex !== undefined) {
|
||||
if (focusedTagIndex === items.length - 1) {
|
||||
setFocusedTagIndex(undefined)
|
||||
return
|
||||
}
|
||||
setFocusedTagIndex(focusedTagIndex + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const removeItem = (index: number) => {
|
||||
if (!items) return
|
||||
const newItems = [...items]
|
||||
newItems.splice(index, 1)
|
||||
onChange(newItems)
|
||||
}
|
||||
|
||||
const addItem = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
if (isEmpty(inputValue)) return
|
||||
setInputValue('')
|
||||
onChange(items ? [...items, inputValue.trim()] : [inputValue.trim()])
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrap
|
||||
spacing={1}
|
||||
borderWidth={1}
|
||||
boxShadow={isFocused ? `0 0 0 1px ${colors['blue'][500]}` : undefined}
|
||||
p="2"
|
||||
rounded="md"
|
||||
borderColor={isFocused ? 'blue.500' : 'gray.200'}
|
||||
transitionProperty="box-shadow, border-color"
|
||||
transitionDuration="150ms"
|
||||
transitionTimingFunction="ease-in-out"
|
||||
onClick={() => inputRef.current?.focus()}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<AnimatePresence mode="popLayout">
|
||||
{items?.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, transform: 'translateY(5px)' }}
|
||||
animate={{ opacity: 1, transform: 'translateY(0)' }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.1 }}
|
||||
>
|
||||
<WrapItem>
|
||||
<Tag
|
||||
content={item}
|
||||
onDeleteClick={() => removeItem(index)}
|
||||
isFocused={focusedTagIndex === index}
|
||||
/>
|
||||
</WrapItem>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
<WrapItem>
|
||||
<form onSubmit={addItem}>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
h="24px"
|
||||
p="0"
|
||||
borderWidth={0}
|
||||
focusBorderColor="transparent"
|
||||
size="sm"
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
placeholder={items && items.length === 0 ? placeholder : undefined}
|
||||
/>
|
||||
</form>
|
||||
</WrapItem>
|
||||
</Wrap>
|
||||
)
|
||||
}
|
||||
|
||||
const Tag = ({
|
||||
isFocused,
|
||||
content,
|
||||
onDeleteClick,
|
||||
}: {
|
||||
isFocused?: boolean
|
||||
content: string
|
||||
onDeleteClick: () => void
|
||||
}) => (
|
||||
<HStack
|
||||
spacing={0.5}
|
||||
borderWidth="1px"
|
||||
pl="1"
|
||||
rounded="sm"
|
||||
maxW="100%"
|
||||
borderColor={isFocused ? 'blue.500' : undefined}
|
||||
boxShadow={isFocused ? `0 0 0 1px ${colors['blue'][500]}` : undefined}
|
||||
>
|
||||
<Text fontSize="sm" noOfLines={1}>
|
||||
{content}
|
||||
</Text>
|
||||
<IconButton
|
||||
size="xs"
|
||||
icon={<CloseIcon />}
|
||||
aria-label="Remove tag"
|
||||
variant="ghost"
|
||||
onClick={onDeleteClick}
|
||||
/>
|
||||
</HStack>
|
||||
)
|
@ -22,6 +22,7 @@ import { isEmpty } from '@typebot.io/lib'
|
||||
import { useGraph } from '@/features/graph/providers/GraphProvider'
|
||||
import { ButtonsItemSettings } from './ButtonsItemSettings'
|
||||
import { useTranslate } from '@tolgee/react'
|
||||
import { convertStrToList } from '@typebot.io/lib/convertStrToList'
|
||||
|
||||
type Props = {
|
||||
item: ButtonItem
|
||||
@ -70,26 +71,18 @@ export const ButtonsItemNode = ({ item, indices, isMouseOver }: Props) => {
|
||||
|
||||
const handleEditableChange = (val: string) => {
|
||||
if (val.length - itemValue.length && val.endsWith('\n')) return
|
||||
const splittedBreakLines = val.split('\n')
|
||||
const splittedCommas = val.split(',')
|
||||
const isPastingMultipleItems =
|
||||
val.length - itemValue.length > 1 &&
|
||||
(splittedBreakLines.length > 2 || splittedCommas.length > 2)
|
||||
if (isPastingMultipleItems) {
|
||||
const values =
|
||||
splittedBreakLines.length > 2 ? splittedBreakLines : splittedCommas
|
||||
return values.forEach((v, i) => {
|
||||
if (i === 0) {
|
||||
setItemValue(v)
|
||||
} else {
|
||||
createItem(
|
||||
{ content: v.trim() },
|
||||
{ ...indices, itemIndex: indices.itemIndex + i }
|
||||
)
|
||||
}
|
||||
if (val.length - itemValue.length === 1) return setItemValue(val)
|
||||
const values = convertStrToList(val)
|
||||
if (values.length === 1) {
|
||||
setItemValue(values[0])
|
||||
} else {
|
||||
values.forEach((v, i) => {
|
||||
createItem(
|
||||
{ content: v },
|
||||
{ ...indices, itemIndex: indices.itemIndex + i }
|
||||
)
|
||||
})
|
||||
}
|
||||
setItemValue(val)
|
||||
}
|
||||
|
||||
const handlePlusClick = () => {
|
||||
|
@ -24,10 +24,11 @@ import {
|
||||
ForgedBlockDefinition,
|
||||
ForgedBlock,
|
||||
} from '@typebot.io/forge-repository/types'
|
||||
import { PrimitiveList } from '@/components/PrimitiveList'
|
||||
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
|
||||
import { CodeEditor } from '@/components/inputs/CodeEditor'
|
||||
import { getZodInnerSchema } from '../../helpers/getZodInnerSchema'
|
||||
import { TagsInput } from '@/components/TagsInput'
|
||||
import { PrimitiveList } from '@/components/PrimitiveList'
|
||||
|
||||
const mdComponents = {
|
||||
a: ({ href, children }) => (
|
||||
@ -316,28 +317,43 @@ const ZodArrayContent = ({
|
||||
const type = schema._def.type._def.innerType?._def.typeName
|
||||
if (type === 'ZodString' || type === 'ZodNumber' || type === 'ZodEnum')
|
||||
return (
|
||||
<Stack spacing={0}>
|
||||
<Stack
|
||||
spacing={0}
|
||||
marginTop={layout?.mergeWithLastField ? '-3' : undefined}
|
||||
>
|
||||
{layout?.label && <FormLabel>{layout.label}</FormLabel>}
|
||||
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
|
||||
<PrimitiveList
|
||||
onItemsChange={(items) => {
|
||||
onDataChange(items)
|
||||
}}
|
||||
initialItems={data}
|
||||
addLabel={`Add ${layout?.itemLabel ?? ''}`}
|
||||
>
|
||||
{({ item, onItemChange }) => (
|
||||
<ZodFieldLayout
|
||||
schema={schema._def.type}
|
||||
data={item}
|
||||
blockDef={blockDef}
|
||||
blockOptions={blockOptions}
|
||||
isInAccordion={isInAccordion}
|
||||
onDataChange={onItemChange}
|
||||
width="full"
|
||||
/>
|
||||
)}
|
||||
</PrimitiveList>
|
||||
<Stack
|
||||
p="4"
|
||||
rounded="md"
|
||||
flex="1"
|
||||
borderWidth="1px"
|
||||
borderTopWidth={layout?.mergeWithLastField ? '0' : undefined}
|
||||
borderTopRadius={layout?.mergeWithLastField ? '0' : undefined}
|
||||
pt={layout?.mergeWithLastField ? '5' : undefined}
|
||||
>
|
||||
{type === 'ZodString' ? (
|
||||
<TagsInput items={data} onChange={onDataChange} />
|
||||
) : (
|
||||
<PrimitiveList
|
||||
onItemsChange={(items) => {
|
||||
onDataChange(items)
|
||||
}}
|
||||
initialItems={data}
|
||||
addLabel={`Add ${layout?.itemLabel ?? ''}`}
|
||||
>
|
||||
{({ item, onItemChange }) => (
|
||||
<ZodFieldLayout
|
||||
schema={schema._def.type}
|
||||
data={item}
|
||||
blockDef={blockDef}
|
||||
blockOptions={blockOptions}
|
||||
isInAccordion={isInAccordion}
|
||||
onDataChange={onItemChange}
|
||||
width="full"
|
||||
/>
|
||||
)}
|
||||
</PrimitiveList>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
|
@ -2,10 +2,9 @@ import { FormControl, FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { Settings } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { env } from '@typebot.io/env'
|
||||
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
|
||||
import { PrimitiveList } from '@/components/PrimitiveList'
|
||||
import { TagsInput } from '@/components/TagsInput'
|
||||
import { env } from '@typebot.io/env'
|
||||
|
||||
type Props = {
|
||||
security: Settings['security']
|
||||
@ -30,20 +29,11 @@ export const SecurityForm = ({ security, onUpdate }: Props) => {
|
||||
By default your bot can be executed on any website.
|
||||
</MoreInfoTooltip>
|
||||
</FormLabel>
|
||||
<PrimitiveList
|
||||
initialItems={security?.allowedOrigins}
|
||||
onItemsChange={updateItems}
|
||||
addLabel="Add URL"
|
||||
>
|
||||
{({ item, onItemChange }) => (
|
||||
<TextInput
|
||||
width="full"
|
||||
defaultValue={item}
|
||||
onChange={onItemChange}
|
||||
placeholder={env.NEXT_PUBLIC_VIEWER_URL[0]}
|
||||
/>
|
||||
)}
|
||||
</PrimitiveList>
|
||||
<TagsInput
|
||||
items={security?.allowedOrigins}
|
||||
onChange={updateItems}
|
||||
placeholder={env.NEXT_PUBLIC_VIEWER_URL[0]}
|
||||
/>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
)
|
||||
|
@ -21,7 +21,7 @@
|
||||
"@typebot.io/js": "workspace:*",
|
||||
"@typebot.io/nextjs": "workspace:*",
|
||||
"@typebot.io/prisma": "workspace:*",
|
||||
"ai": "3.1.12",
|
||||
"ai": "3.1.34",
|
||||
"bot-engine": "workspace:*",
|
||||
"cors": "2.8.5",
|
||||
"google-spreadsheet": "4.1.1",
|
||||
|
@ -20,7 +20,7 @@
|
||||
"@typebot.io/variables": "workspace:*",
|
||||
"@udecode/plate-common": "30.4.5",
|
||||
"@typebot.io/logic": "workspace:*",
|
||||
"ai": "3.1.12",
|
||||
"ai": "3.1.34",
|
||||
"chrono-node": "2.7.6",
|
||||
"date-fns": "2.30.0",
|
||||
"date-fns-tz": "2.0.0",
|
||||
|
42
packages/forge/blocks/anthropic/actions/generateVariables.ts
Normal file
42
packages/forge/blocks/anthropic/actions/generateVariables.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { createAction } from '@typebot.io/forge'
|
||||
import { auth } from '../auth'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { createAnthropic } from '@ai-sdk/anthropic'
|
||||
import { parseGenerateVariablesOptions } from '@typebot.io/openai-block/shared/parseGenerateVariablesOptions'
|
||||
import { runGenerateVariables } from '@typebot.io/openai-block/shared/runGenerateVariables'
|
||||
import { anthropicModels } from '../constants'
|
||||
|
||||
export const generateVariables = createAction({
|
||||
name: 'Generate variables',
|
||||
auth,
|
||||
options: parseGenerateVariablesOptions({ modelFetch: anthropicModels }),
|
||||
turnableInto: [
|
||||
{
|
||||
blockId: 'openai',
|
||||
},
|
||||
{
|
||||
blockId: 'mistral',
|
||||
},
|
||||
],
|
||||
getSetVariableIds: (options) =>
|
||||
options.variablesToExtract?.map((v) => v.variableId).filter(isDefined) ??
|
||||
[],
|
||||
run: {
|
||||
server: ({ credentials, options, variables, logs }) => {
|
||||
if (credentials?.apiKey === undefined)
|
||||
return logs.add('No API key provided')
|
||||
|
||||
if (options.model === undefined) return logs.add('No model provided')
|
||||
|
||||
return runGenerateVariables({
|
||||
model: createAnthropic({
|
||||
apiKey: credentials.apiKey,
|
||||
})(options.model),
|
||||
prompt: options.prompt,
|
||||
variablesToExtract: options.variablesToExtract,
|
||||
variables,
|
||||
logs,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
@ -2,6 +2,7 @@ import { createBlock } from '@typebot.io/forge'
|
||||
import { AnthropicLogo } from './logo'
|
||||
import { auth } from './auth'
|
||||
import { createChatMessage } from './actions/createChatMessage'
|
||||
import { generateVariables } from './actions/generateVariables'
|
||||
|
||||
export const anthropicBlock = createBlock({
|
||||
id: 'anthropic',
|
||||
@ -9,5 +10,5 @@ export const anthropicBlock = createBlock({
|
||||
tags: ['ai', 'chat', 'completion', 'claude', 'anthropic'],
|
||||
LightLogo: AnthropicLogo,
|
||||
auth,
|
||||
actions: [createChatMessage],
|
||||
actions: [createChatMessage, generateVariables],
|
||||
})
|
||||
|
@ -16,7 +16,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.20.6",
|
||||
"ai": "3.1.12",
|
||||
"@ai-sdk/anthropic": "0.0.21",
|
||||
"@typebot.io/openai-block": "workspace:*",
|
||||
"ai": "3.1.34",
|
||||
"ky": "1.2.4"
|
||||
}
|
||||
}
|
@ -14,6 +14,6 @@
|
||||
"typescript": "5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "3.1.12"
|
||||
"ai": "3.1.34"
|
||||
}
|
||||
}
|
@ -3,9 +3,8 @@ import { isDefined } from '@typebot.io/lib'
|
||||
import { auth } from '../auth'
|
||||
import { parseMessages } from '../helpers/parseMessages'
|
||||
import { createMistral } from '@ai-sdk/mistral'
|
||||
import { apiBaseUrl } from '../constants'
|
||||
import ky from 'ky'
|
||||
import { generateText, streamText } from 'ai'
|
||||
import { fetchModels } from '../helpers/fetchModels'
|
||||
|
||||
const nativeMessageContentSchema = {
|
||||
content: option.string.layout({
|
||||
@ -98,19 +97,7 @@ export const createChatCompletion = createAction({
|
||||
{
|
||||
id: 'fetchModels',
|
||||
dependencies: [],
|
||||
fetch: async ({ credentials }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const { data } = await ky
|
||||
.get(apiBaseUrl + '/v1/models', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${credentials.apiKey}`,
|
||||
},
|
||||
})
|
||||
.json<{ data: { id: string }[] }>()
|
||||
|
||||
return data.map((model) => model.id)
|
||||
},
|
||||
fetch: fetchModels,
|
||||
},
|
||||
],
|
||||
run: {
|
||||
|
53
packages/forge/blocks/mistral/actions/generateVariables.ts
Normal file
53
packages/forge/blocks/mistral/actions/generateVariables.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { createAction } from '@typebot.io/forge'
|
||||
import { auth } from '../auth'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { createMistral } from '@ai-sdk/mistral'
|
||||
import { fetchModels } from '../helpers/fetchModels'
|
||||
import { parseGenerateVariablesOptions } from '@typebot.io/openai-block/shared/parseGenerateVariablesOptions'
|
||||
import { runGenerateVariables } from '@typebot.io/openai-block/shared/runGenerateVariables'
|
||||
|
||||
export const generateVariables = createAction({
|
||||
name: 'Generate variables',
|
||||
auth,
|
||||
options: parseGenerateVariablesOptions({ modelFetch: 'fetchModels' }),
|
||||
fetchers: [
|
||||
{
|
||||
id: 'fetchModels',
|
||||
dependencies: [],
|
||||
fetch: fetchModels,
|
||||
},
|
||||
],
|
||||
turnableInto: [
|
||||
{
|
||||
blockId: 'openai',
|
||||
},
|
||||
{
|
||||
blockId: 'anthropic',
|
||||
transform: (options) => ({
|
||||
...options,
|
||||
model: undefined,
|
||||
}),
|
||||
},
|
||||
],
|
||||
getSetVariableIds: (options) =>
|
||||
options.variablesToExtract?.map((v) => v.variableId).filter(isDefined) ??
|
||||
[],
|
||||
run: {
|
||||
server: ({ credentials, options, variables, logs }) => {
|
||||
if (credentials?.apiKey === undefined)
|
||||
return logs.add('No API key provided')
|
||||
|
||||
if (options.model === undefined) return logs.add('No model provided')
|
||||
|
||||
return runGenerateVariables({
|
||||
model: createMistral({
|
||||
apiKey: credentials.apiKey,
|
||||
})(options.model),
|
||||
variablesToExtract: options.variablesToExtract,
|
||||
prompt: options.prompt,
|
||||
variables,
|
||||
logs,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
20
packages/forge/blocks/mistral/helpers/fetchModels.ts
Normal file
20
packages/forge/blocks/mistral/helpers/fetchModels.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import ky from 'ky'
|
||||
import { apiBaseUrl } from '../constants'
|
||||
|
||||
export const fetchModels = async ({
|
||||
credentials,
|
||||
}: {
|
||||
credentials?: { apiKey?: string }
|
||||
}) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const { data } = await ky
|
||||
.get(apiBaseUrl + '/v1/models', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${credentials.apiKey}`,
|
||||
},
|
||||
})
|
||||
.json<{ data: { id: string }[] }>()
|
||||
|
||||
return data.map((model) => model.id)
|
||||
}
|
@ -2,6 +2,7 @@ import { createBlock } from '@typebot.io/forge'
|
||||
import { MistralLogo } from './logo'
|
||||
import { auth } from './auth'
|
||||
import { createChatCompletion } from './actions/createChatCompletion'
|
||||
import { generateVariables } from './actions/generateVariables'
|
||||
|
||||
export const mistralBlock = createBlock({
|
||||
id: 'mistral',
|
||||
@ -9,6 +10,6 @@ export const mistralBlock = createBlock({
|
||||
tags: ['ai', 'chat', 'completion'],
|
||||
LightLogo: MistralLogo,
|
||||
auth,
|
||||
actions: [createChatCompletion],
|
||||
actions: [createChatCompletion, generateVariables],
|
||||
docsUrl: 'https://docs.typebot.io/forge/blocks/mistral',
|
||||
})
|
||||
|
@ -14,8 +14,9 @@
|
||||
"typescript": "5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/mistral": "0.0.11",
|
||||
"ai": "3.1.12",
|
||||
"@ai-sdk/mistral": "0.0.18",
|
||||
"@typebot.io/openai-block": "workspace:*",
|
||||
"ai": "3.1.34",
|
||||
"ky": "1.2.4"
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { createAction } from '@typebot.io/forge'
|
||||
import OpenAI, { ClientOptions } from 'openai'
|
||||
import { defaultOpenAIOptions } from '../constants'
|
||||
import { auth } from '../auth'
|
||||
import { baseOptions } from '../baseOptions'
|
||||
@ -8,6 +7,7 @@ import { getChatCompletionSetVarIds } from '../shared/getChatCompletionSetVarIds
|
||||
import { runChatCompletion } from '../shared/runChatCompletion'
|
||||
import { runChatCompletionStream } from '../shared/runChatCompletionStream'
|
||||
import { getChatCompletionStreamVarId } from '../shared/getChatCompletionStreamVarId'
|
||||
import { fetchGPTModels } from '../helpers/fetchModels'
|
||||
|
||||
export const createChatCompletion = createAction({
|
||||
name: 'Create chat completion',
|
||||
@ -45,34 +45,12 @@ export const createChatCompletion = createAction({
|
||||
{
|
||||
id: 'fetchModels',
|
||||
dependencies: ['baseUrl', 'apiVersion'],
|
||||
fetch: async ({ credentials, options }) => {
|
||||
if (!credentials?.apiKey) return []
|
||||
|
||||
const baseUrl = options?.baseUrl ?? defaultOpenAIOptions.baseUrl
|
||||
const config = {
|
||||
apiKey: credentials.apiKey,
|
||||
baseURL: baseUrl ?? defaultOpenAIOptions.baseUrl,
|
||||
defaultHeaders: {
|
||||
'api-key': credentials.apiKey,
|
||||
},
|
||||
defaultQuery: options?.apiVersion
|
||||
? {
|
||||
'api-version': options.apiVersion,
|
||||
}
|
||||
: undefined,
|
||||
} satisfies ClientOptions
|
||||
|
||||
const openai = new OpenAI(config)
|
||||
|
||||
const models = await openai.models.list()
|
||||
|
||||
return (
|
||||
models.data
|
||||
.filter((model) => model.id.includes('gpt'))
|
||||
.sort((a, b) => b.created - a.created)
|
||||
.map((model) => model.id) ?? []
|
||||
)
|
||||
},
|
||||
fetch: ({ credentials, options }) =>
|
||||
fetchGPTModels({
|
||||
apiKey: credentials?.apiKey,
|
||||
baseUrl: options.baseUrl,
|
||||
apiVersion: options.apiVersion,
|
||||
}),
|
||||
},
|
||||
],
|
||||
run: {
|
||||
|
61
packages/forge/blocks/openai/actions/generateVariables.ts
Normal file
61
packages/forge/blocks/openai/actions/generateVariables.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { createAction } from '@typebot.io/forge'
|
||||
import { auth } from '../auth'
|
||||
import { baseOptions } from '../baseOptions'
|
||||
import { fetchGPTModels } from '../helpers/fetchModels'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { runGenerateVariables } from '../shared/runGenerateVariables'
|
||||
import { parseGenerateVariablesOptions } from '../shared/parseGenerateVariablesOptions'
|
||||
import { createOpenAI } from '@ai-sdk/openai'
|
||||
|
||||
export const generateVariables = createAction({
|
||||
name: 'Generate variables',
|
||||
auth,
|
||||
baseOptions,
|
||||
options: parseGenerateVariablesOptions({ modelFetch: 'fetchModels' }),
|
||||
fetchers: [
|
||||
{
|
||||
id: 'fetchModels',
|
||||
dependencies: ['baseUrl', 'apiVersion'],
|
||||
fetch: ({ credentials, options }) =>
|
||||
fetchGPTModels({
|
||||
apiKey: credentials?.apiKey,
|
||||
baseUrl: options.baseUrl,
|
||||
apiVersion: options.apiVersion,
|
||||
}),
|
||||
},
|
||||
],
|
||||
turnableInto: [
|
||||
{
|
||||
blockId: 'mistral',
|
||||
},
|
||||
{
|
||||
blockId: 'anthropic',
|
||||
transform: (options) => ({
|
||||
...options,
|
||||
model: undefined,
|
||||
}),
|
||||
},
|
||||
],
|
||||
getSetVariableIds: (options) =>
|
||||
options.variablesToExtract?.map((v) => v.variableId).filter(isDefined) ??
|
||||
[],
|
||||
run: {
|
||||
server: ({ credentials, options, variables, logs }) => {
|
||||
if (credentials?.apiKey === undefined)
|
||||
return logs.add('No API key provided')
|
||||
|
||||
if (options.model === undefined) return logs.add('No model provided')
|
||||
|
||||
return runGenerateVariables({
|
||||
model: createOpenAI({
|
||||
apiKey: credentials.apiKey,
|
||||
compatibility: 'strict',
|
||||
})(options.model),
|
||||
prompt: options.prompt,
|
||||
variablesToExtract: options.variablesToExtract,
|
||||
variables,
|
||||
logs,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
40
packages/forge/blocks/openai/helpers/fetchModels.ts
Normal file
40
packages/forge/blocks/openai/helpers/fetchModels.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import OpenAI, { ClientOptions } from 'openai'
|
||||
import { defaultOpenAIOptions } from '../constants'
|
||||
|
||||
type Props = {
|
||||
apiKey?: string
|
||||
baseUrl?: string
|
||||
apiVersion?: string
|
||||
}
|
||||
|
||||
export const fetchGPTModels = async ({
|
||||
apiKey,
|
||||
baseUrl = defaultOpenAIOptions.baseUrl,
|
||||
apiVersion,
|
||||
}: Props) => {
|
||||
if (!apiKey) return []
|
||||
|
||||
const config = {
|
||||
apiKey: apiKey,
|
||||
baseURL: baseUrl ?? defaultOpenAIOptions.baseUrl,
|
||||
defaultHeaders: {
|
||||
'api-key': apiKey,
|
||||
},
|
||||
defaultQuery: apiVersion
|
||||
? {
|
||||
'api-version': apiVersion,
|
||||
}
|
||||
: undefined,
|
||||
} satisfies ClientOptions
|
||||
|
||||
const openai = new OpenAI(config)
|
||||
|
||||
const models = await openai.models.list()
|
||||
|
||||
return (
|
||||
models.data
|
||||
.filter((model) => model.id.includes('gpt'))
|
||||
.sort((a, b) => b.created - a.created)
|
||||
.map((model) => model.id) ?? []
|
||||
)
|
||||
}
|
@ -5,6 +5,7 @@ import { createBlock } from '@typebot.io/forge'
|
||||
import { auth } from './auth'
|
||||
import { baseOptions } from './baseOptions'
|
||||
import { askAssistant } from './actions/askAssistant'
|
||||
import { generateVariables } from './actions/generateVariables'
|
||||
|
||||
export const openAIBlock = createBlock({
|
||||
id: 'openai' as const,
|
||||
@ -14,6 +15,11 @@ export const openAIBlock = createBlock({
|
||||
DarkLogo: OpenAIDarkLogo,
|
||||
auth,
|
||||
options: baseOptions,
|
||||
actions: [createChatCompletion, askAssistant, createSpeech],
|
||||
actions: [
|
||||
createChatCompletion,
|
||||
askAssistant,
|
||||
generateVariables,
|
||||
createSpeech,
|
||||
],
|
||||
docsUrl: 'https://docs.typebot.io/forge/blocks/openai',
|
||||
})
|
||||
|
@ -7,16 +7,17 @@
|
||||
"author": "Baptiste Arnaud",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"ai": "3.1.12",
|
||||
"@ai-sdk/openai": "0.0.31",
|
||||
"ai": "3.1.34",
|
||||
"openai": "4.47.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typebot.io/forge": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@types/react": "18.2.15",
|
||||
"typescript": "5.4.5",
|
||||
"@typebot.io/lib": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@typebot.io/variables": "workspace:*",
|
||||
"ky": "1.2.4"
|
||||
"@types/react": "18.2.15",
|
||||
"ky": "1.2.4",
|
||||
"typescript": "5.4.5"
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
import { option } from '@typebot.io/forge'
|
||||
import { z } from '@typebot.io/forge/zod'
|
||||
import { baseOptions } from '../baseOptions'
|
||||
|
||||
const extractInfoBaseShape = {
|
||||
variableId: option.string.layout({
|
||||
inputType: 'variableDropdown',
|
||||
}),
|
||||
description: option.string.layout({
|
||||
label: 'Description',
|
||||
accordion: 'Advanced',
|
||||
}),
|
||||
isRequired: option.boolean.layout({
|
||||
label: 'Is required',
|
||||
moreInfoTooltip:
|
||||
'If set to false, there is a chance the variable will be empty',
|
||||
accordion: 'Advanced',
|
||||
defaultValue: true,
|
||||
}),
|
||||
}
|
||||
|
||||
export const toolParametersSchema = option
|
||||
.array(
|
||||
option.discriminatedUnion('type', [
|
||||
option
|
||||
.object({
|
||||
type: option.literal('string'),
|
||||
})
|
||||
.extend(extractInfoBaseShape),
|
||||
option
|
||||
.object({
|
||||
type: option.literal('number'),
|
||||
})
|
||||
.extend(extractInfoBaseShape),
|
||||
option
|
||||
.object({
|
||||
type: option.literal('boolean'),
|
||||
})
|
||||
.extend(extractInfoBaseShape),
|
||||
option
|
||||
.object({
|
||||
type: option.literal('enum'),
|
||||
values: option
|
||||
.array(option.string)
|
||||
.layout({ itemLabel: 'possible value', mergeWithLastField: true }),
|
||||
})
|
||||
.extend(extractInfoBaseShape),
|
||||
])
|
||||
)
|
||||
.layout({
|
||||
itemLabel: 'variable mapping',
|
||||
accordion: 'Schema',
|
||||
})
|
||||
|
||||
type Props = {
|
||||
defaultModel?: string
|
||||
modelFetch: string | readonly [string, ...string[]]
|
||||
modelHelperText?: string
|
||||
}
|
||||
|
||||
export const parseGenerateVariablesOptions = ({
|
||||
defaultModel,
|
||||
modelFetch,
|
||||
modelHelperText,
|
||||
}: Props) =>
|
||||
option.object({
|
||||
model:
|
||||
typeof modelFetch === 'string'
|
||||
? option.string.layout({
|
||||
placeholder: 'Select a model',
|
||||
label: 'Model',
|
||||
defaultValue: defaultModel,
|
||||
fetcher: modelFetch,
|
||||
helperText: modelHelperText,
|
||||
})
|
||||
: option.enum(modelFetch).layout({
|
||||
placeholder: 'Select a model',
|
||||
label: 'Model',
|
||||
defaultValue: defaultModel,
|
||||
helperText: modelHelperText,
|
||||
}),
|
||||
prompt: option.string.layout({
|
||||
label: 'Prompt',
|
||||
placeholder: 'Type your text here',
|
||||
inputType: 'textarea',
|
||||
isRequired: true,
|
||||
moreInfoTooltip:
|
||||
'Meant to guide the model on what to generate. i.e. "Generate a role-playing game character", "Extract the company name from this text", etc.',
|
||||
}),
|
||||
variablesToExtract: toolParametersSchema,
|
||||
})
|
||||
|
||||
export type GenerateVariablesOptions = z.infer<
|
||||
ReturnType<typeof parseGenerateVariablesOptions>
|
||||
> &
|
||||
z.infer<typeof baseOptions>
|
101
packages/forge/blocks/openai/shared/runGenerateVariables.ts
Normal file
101
packages/forge/blocks/openai/shared/runGenerateVariables.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { LogsStore, VariableStore } from '@typebot.io/forge/types'
|
||||
import {
|
||||
GenerateVariablesOptions,
|
||||
toolParametersSchema,
|
||||
} from './parseGenerateVariablesOptions'
|
||||
import { generateObject, LanguageModel } from 'ai'
|
||||
import { Variable } from '@typebot.io/variables/types'
|
||||
import { z } from '@typebot.io/forge/zod'
|
||||
import { isNotEmpty } from '@typebot.io/lib/utils'
|
||||
|
||||
type Props = {
|
||||
model: LanguageModel
|
||||
variables: VariableStore
|
||||
logs: LogsStore
|
||||
} & Pick<GenerateVariablesOptions, 'variablesToExtract' | 'prompt'>
|
||||
|
||||
export const runGenerateVariables = async ({
|
||||
variablesToExtract,
|
||||
model,
|
||||
prompt,
|
||||
variables: variablesStore,
|
||||
logs,
|
||||
}: Props) => {
|
||||
if (!prompt) return logs.add('No prompt provided')
|
||||
const variables = variablesStore.list()
|
||||
|
||||
const schema = convertVariablesToExtractToSchema({
|
||||
variablesToExtract,
|
||||
variables,
|
||||
})
|
||||
if (!schema) {
|
||||
logs.add('Could not parse variables to extract')
|
||||
return
|
||||
}
|
||||
|
||||
const hasOptionalVariables = variablesToExtract?.some(
|
||||
(variableToExtract) => variableToExtract.isRequired === false
|
||||
)
|
||||
|
||||
const { object } = await generateObject({
|
||||
model,
|
||||
schema,
|
||||
prompt:
|
||||
`${prompt}\n\nYou should generate a JSON object` +
|
||||
(hasOptionalVariables
|
||||
? ' and provide empty values if the information is not there or if you are unsure.'
|
||||
: '.'),
|
||||
})
|
||||
|
||||
Object.entries(object).forEach(([key, value]) => {
|
||||
if (value === null) return
|
||||
const existingVariable = variables.find((v) => v.name === key)
|
||||
if (!existingVariable) return
|
||||
variablesStore.set(existingVariable.id, value)
|
||||
})
|
||||
}
|
||||
|
||||
const convertVariablesToExtractToSchema = ({
|
||||
variablesToExtract,
|
||||
variables,
|
||||
}: {
|
||||
variablesToExtract: z.infer<typeof toolParametersSchema> | undefined
|
||||
variables: Variable[]
|
||||
}): z.ZodTypeAny | undefined => {
|
||||
if (!variablesToExtract || variablesToExtract?.length === 0) return
|
||||
|
||||
const shape: z.ZodRawShape = {}
|
||||
variablesToExtract.forEach((variableToExtract) => {
|
||||
if (!variableToExtract) return
|
||||
const matchingVariable = variables.find(
|
||||
(v) => v.id === variableToExtract.variableId
|
||||
)
|
||||
if (!matchingVariable) return
|
||||
switch (variableToExtract.type) {
|
||||
case 'string':
|
||||
shape[matchingVariable.name] = z.string()
|
||||
break
|
||||
case 'number':
|
||||
shape[matchingVariable.name] = z.number()
|
||||
break
|
||||
case 'boolean':
|
||||
shape[matchingVariable.name] = z.boolean()
|
||||
break
|
||||
case 'enum': {
|
||||
if (!variableToExtract.values || variableToExtract.values.length === 0)
|
||||
return
|
||||
shape[matchingVariable.name] = z.enum(variableToExtract.values as any)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (variableToExtract.isRequired === false)
|
||||
shape[matchingVariable.name] = shape[matchingVariable.name].optional()
|
||||
|
||||
if (isNotEmpty(variableToExtract.description))
|
||||
shape[matchingVariable.name] = shape[matchingVariable.name].describe(
|
||||
variableToExtract.description
|
||||
)
|
||||
})
|
||||
|
||||
return z.object(shape)
|
||||
}
|
@ -23,6 +23,7 @@ export interface ZodLayoutMetadata<
|
||||
isHidden?: boolean | ((currentObj: Record<string, any>) => boolean)
|
||||
isDebounceDisabled?: boolean
|
||||
hiddenItems?: string[]
|
||||
mergeWithLastField?: boolean
|
||||
}
|
||||
|
||||
declare module 'zod' {
|
||||
|
13
packages/lib/convertStrToList.ts
Normal file
13
packages/lib/convertStrToList.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const convertStrToList = (str: string): string[] => {
|
||||
const splittedBreakLines = str.split('\n')
|
||||
const splittedCommas = str.split(',')
|
||||
const isPastingMultipleItems =
|
||||
str.length > 1 &&
|
||||
(splittedBreakLines.length >= 2 || splittedCommas.length >= 2)
|
||||
if (isPastingMultipleItems) {
|
||||
const values =
|
||||
splittedBreakLines.length >= 2 ? splittedBreakLines : splittedCommas
|
||||
return values.map((v) => v.trim())
|
||||
}
|
||||
return [str.trim()]
|
||||
}
|
213
pnpm-lock.yaml
generated
213
pnpm-lock.yaml
generated
@ -421,8 +421,8 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/prisma
|
||||
ai:
|
||||
specifier: 3.1.12
|
||||
version: 3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
specifier: 3.1.34
|
||||
version: 3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
bot-engine:
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/deprecated/bot-engine
|
||||
@ -754,8 +754,8 @@ importers:
|
||||
specifier: 30.4.5
|
||||
version: 30.4.5(@types/react@18.2.15)(immer@10.0.2)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0)(slate-history@0.100.0)(slate-hyperscript@0.100.0)(slate-react@0.102.0)(slate@0.102.0)
|
||||
ai:
|
||||
specifier: 3.1.12
|
||||
version: 3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
specifier: 3.1.34
|
||||
version: 3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
chrono-node:
|
||||
specifier: 2.7.6
|
||||
version: 2.7.6
|
||||
@ -1284,12 +1284,18 @@ importers:
|
||||
|
||||
packages/forge/blocks/anthropic:
|
||||
dependencies:
|
||||
'@ai-sdk/anthropic':
|
||||
specifier: 0.0.21
|
||||
version: 0.0.21(zod@3.22.4)
|
||||
'@anthropic-ai/sdk':
|
||||
specifier: 0.20.6
|
||||
version: 0.20.6
|
||||
'@typebot.io/openai-block':
|
||||
specifier: workspace:*
|
||||
version: link:../openai
|
||||
ai:
|
||||
specifier: 3.1.12
|
||||
version: 3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
specifier: 3.1.34
|
||||
version: 3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
ky:
|
||||
specifier: 1.2.4
|
||||
version: 1.2.4
|
||||
@ -1355,8 +1361,8 @@ importers:
|
||||
packages/forge/blocks/difyAi:
|
||||
dependencies:
|
||||
ai:
|
||||
specifier: 3.1.12
|
||||
version: 3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
specifier: 3.1.34
|
||||
version: 3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
devDependencies:
|
||||
'@typebot.io/forge':
|
||||
specifier: workspace:*
|
||||
@ -1402,11 +1408,14 @@ importers:
|
||||
packages/forge/blocks/mistral:
|
||||
dependencies:
|
||||
'@ai-sdk/mistral':
|
||||
specifier: 0.0.11
|
||||
version: 0.0.11(zod@3.22.4)
|
||||
specifier: 0.0.18
|
||||
version: 0.0.18(zod@3.22.4)
|
||||
'@typebot.io/openai-block':
|
||||
specifier: workspace:*
|
||||
version: link:../openai
|
||||
ai:
|
||||
specifier: 3.1.12
|
||||
version: 3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
specifier: 3.1.34
|
||||
version: 3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
ky:
|
||||
specifier: 1.2.4
|
||||
version: 1.2.4
|
||||
@ -1478,9 +1487,12 @@ importers:
|
||||
|
||||
packages/forge/blocks/openai:
|
||||
dependencies:
|
||||
'@ai-sdk/openai':
|
||||
specifier: 0.0.31
|
||||
version: 0.0.31(zod@3.22.4)
|
||||
ai:
|
||||
specifier: 3.1.12
|
||||
version: 3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
specifier: 3.1.34
|
||||
version: 3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4)
|
||||
openai:
|
||||
specifier: 4.47.1
|
||||
version: 4.47.1
|
||||
@ -2038,22 +2050,41 @@ packages:
|
||||
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/@ai-sdk/mistral@0.0.11(zod@3.22.4):
|
||||
resolution: {integrity: sha512-Y/2V7BMwyaTnVRfhs6YhI5MGcQgjBrTwo2K6CftUAjJvNIDtSJ+eVc9hCuw02uMvTScfeiTB6lZ8OrzGyCNHoQ==}
|
||||
/@ai-sdk/anthropic@0.0.21(zod@3.22.4):
|
||||
resolution: {integrity: sha512-QjVnTbfbAmfMjDqLbcZFC4pKBvp4RqzrZJQF3mzulSkeXWqNZo9G9oV7W1PDbMA3o+DJdxRFyTK43aKUBCP31Q==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 0.0.5
|
||||
'@ai-sdk/provider-utils': 0.0.8(zod@3.22.4)
|
||||
'@ai-sdk/provider': 0.0.10
|
||||
'@ai-sdk/provider-utils': 0.0.15(zod@3.22.4)
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider-utils@0.0.8(zod@3.22.4):
|
||||
resolution: {integrity: sha512-J/ZNvFhORd3gCeK3jFvNrxp1Dnvy6PvPq21RJ+OsIEjsoHeKQaHALCWG0aJunXDuzd+Mck/lCg7LqA0qmIbHIg==}
|
||||
/@ai-sdk/mistral@0.0.18(zod@3.22.4):
|
||||
resolution: {integrity: sha512-aNbdyINZU2Kmv6+uLEEbvQJxHChYf1RofIETYAmCZcOk3wU1gReWSjZK7eP9BzehXg1TkeF1UpT60bnzl0++Pg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 0.0.10
|
||||
'@ai-sdk/provider-utils': 0.0.15(zod@3.22.4)
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/openai@0.0.31(zod@3.22.4):
|
||||
resolution: {integrity: sha512-7ehX2N0NzCdxUOYXutwYgu6gdWO+zS/v8pWEd7VW8QpNq3equ0VZ0j+pDUNv4f3GJ449QwySb6+V+DHM9W/pLg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 0.0.10
|
||||
'@ai-sdk/provider-utils': 0.0.15(zod@3.22.4)
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider-utils@0.0.13(zod@3.22.4):
|
||||
resolution: {integrity: sha512-cB2dPm9flj+yin5sjBLFcXdW8sZtAXLE/OLKgz9uHpHM55s7mnwZrDGfO6ot/ukHTxDDJunZLW7qSjgK/u0F1g==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
@ -2061,20 +2092,112 @@ packages:
|
||||
zod:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 0.0.5
|
||||
'@ai-sdk/provider': 0.0.10
|
||||
eventsource-parser: 1.1.2
|
||||
nanoid: 3.3.6
|
||||
secure-json-parse: 2.7.0
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider@0.0.5:
|
||||
resolution: {integrity: sha512-TZDldBZ5clAsNwJ2PSeo/b1uILj9a2lvi0rnOj2RCNZDgaVqFRVIAnKyeHusCRv2lzhPIw03B3fiGI6VoLzOAA==}
|
||||
/@ai-sdk/provider-utils@0.0.15(zod@3.22.4):
|
||||
resolution: {integrity: sha512-eTkIaZc/Ud96DYG40lLuKWJvZ2GoW/wT4KH9r1f3wGUhj5wgQN+bzgdI57z60VOEDuMmDVuILVnTLFe0HNT5Iw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 0.0.10
|
||||
eventsource-parser: 1.1.2
|
||||
nanoid: 3.3.6
|
||||
secure-json-parse: 2.7.0
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider@0.0.10:
|
||||
resolution: {integrity: sha512-NzkrtREQpHID1cTqY/C4CI30PVOaXWKYytDR2EcytmFgnP7Z6+CrGIA/YCnNhYAuUm6Nx+nGpRL/Hmyrv7NYzg==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/react@0.0.1(react@18.2.0)(zod@3.22.4):
|
||||
resolution: {integrity: sha512-y6KXzxRR7vmAgDVnS/hnLPt3RztvWOisANBw47O1o1D2nDeUqTo8E/SNw2J8mzzlRInGaw40EREY8jEf9AcwWQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider-utils': 0.0.13(zod@3.22.4)
|
||||
'@ai-sdk/ui-utils': 0.0.1(zod@3.22.4)
|
||||
react: 18.2.0
|
||||
swr: 2.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/solid@0.0.1(solid-js@1.7.8)(zod@3.22.4):
|
||||
resolution: {integrity: sha512-5WWdoqpemYW66rMZUYF4sbDtZfF96Vt8RtrzpLv+95ZUM1nY1elxAWpHCeOyYEjWJE5+eiKpUs6Jr5mP2/gz8Q==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
solid-js: ^1.7.7
|
||||
peerDependenciesMeta:
|
||||
solid-js:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/ui-utils': 0.0.1(zod@3.22.4)
|
||||
solid-js: 1.7.8
|
||||
solid-swr-store: 0.10.7(solid-js@1.7.8)(swr-store@0.10.6)
|
||||
swr-store: 0.10.6
|
||||
transitivePeerDependencies:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/svelte@0.0.1(svelte@4.2.12)(zod@3.22.4):
|
||||
resolution: {integrity: sha512-bpjTLKOwdcXjJzboq15etT1hdnRI1ErPZweWSsu1/LJlEFzD1M0qpZQwWHwPquYkzeppXOgsLrUZ+9D2RoC47Q==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
svelte: ^3.0.0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
svelte:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider-utils': 0.0.13(zod@3.22.4)
|
||||
'@ai-sdk/ui-utils': 0.0.1(zod@3.22.4)
|
||||
sswr: 2.1.0(svelte@4.2.12)
|
||||
svelte: 4.2.12
|
||||
transitivePeerDependencies:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/ui-utils@0.0.1(zod@3.22.4):
|
||||
resolution: {integrity: sha512-zOr1zIw/EH4fEQvDKsqYG3wY7GW32h8Wrx0lQpSAP59UCA4zgHBH6ogF5oj7+LUuWjT6be9S0G3l/tEPyRyxEw==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
'@ai-sdk/provider-utils': 0.0.13(zod@3.22.4)
|
||||
transitivePeerDependencies:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/vue@0.0.1(vue@3.4.21)(zod@3.22.4):
|
||||
resolution: {integrity: sha512-B3qAW22FYGy1ltobnF7LiPAmARTrCkH15qjw4WAXCnvRohsYOFTDACOBEsXRfa1OHmqWsUOYeNtE/oPhK3ybqw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
vue: ^3.3.4
|
||||
peerDependenciesMeta:
|
||||
vue:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/ui-utils': 0.0.1(zod@3.22.4)
|
||||
swrv: 1.0.4(vue@3.4.21)
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
transitivePeerDependencies:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@alloc/quick-lru@5.2.0:
|
||||
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||
engines: {node: '>=10'}
|
||||
@ -10282,32 +10405,31 @@ packages:
|
||||
indent-string: 5.0.0
|
||||
dev: true
|
||||
|
||||
/ai@3.1.12(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4):
|
||||
resolution: {integrity: sha512-XlurBw1sdgQCFmCTPYjKjpm+fPS6iY+tLb/PYNUEjZn3bhqosAkcqUkGJTsFP49OMAWO1Lm2oPthCakKcn6Lzw==}
|
||||
/ai@3.1.34(openai@4.47.1)(react@18.2.0)(solid-js@1.7.8)(svelte@4.2.12)(vue@3.4.21)(zod@3.22.4):
|
||||
resolution: {integrity: sha512-cFE33IvG3fcUwvVF932AuvFKbKsKi4YK42Vh95Nh0SpWowEumL99dHh7i3LAjS7yqvC+n8n30t+iVO66Ij5PHg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
openai: ^4.42.0
|
||||
react: ^18.2.0
|
||||
solid-js: ^1.7.7
|
||||
react: ^18 || ^19
|
||||
svelte: ^3.0.0 || ^4.0.0
|
||||
vue: ^3.3.4
|
||||
zod: ^3.0.0
|
||||
peerDependenciesMeta:
|
||||
openai:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
solid-js:
|
||||
optional: true
|
||||
svelte:
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
zod:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 0.0.5
|
||||
'@ai-sdk/provider-utils': 0.0.8(zod@3.22.4)
|
||||
'@ai-sdk/provider': 0.0.10
|
||||
'@ai-sdk/provider-utils': 0.0.13(zod@3.22.4)
|
||||
'@ai-sdk/react': 0.0.1(react@18.2.0)(zod@3.22.4)
|
||||
'@ai-sdk/solid': 0.0.1(solid-js@1.7.8)(zod@3.22.4)
|
||||
'@ai-sdk/svelte': 0.0.1(svelte@4.2.12)(zod@3.22.4)
|
||||
'@ai-sdk/ui-utils': 0.0.1(zod@3.22.4)
|
||||
'@ai-sdk/vue': 0.0.1(vue@3.4.21)(zod@3.22.4)
|
||||
eventsource-parser: 1.1.2
|
||||
json-schema: 0.4.0
|
||||
jsondiffpatch: 0.6.0
|
||||
@ -10315,16 +10437,13 @@ packages:
|
||||
openai: 4.47.1
|
||||
react: 18.2.0
|
||||
secure-json-parse: 2.7.0
|
||||
solid-js: 1.7.8
|
||||
solid-swr-store: 0.10.7(solid-js@1.7.8)(swr-store@0.10.6)
|
||||
sswr: 2.0.0(svelte@4.2.12)
|
||||
sswr: 2.1.0(svelte@4.2.12)
|
||||
svelte: 4.2.12
|
||||
swr: 2.2.0(react@18.2.0)
|
||||
swr-store: 0.10.6
|
||||
swrv: 1.0.4(vue@3.4.21)
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
zod: 3.22.4
|
||||
zod-to-json-schema: 3.22.5(zod@3.22.4)
|
||||
transitivePeerDependencies:
|
||||
- solid-js
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/ajv-draft-04@1.0.0(ajv@8.12.0):
|
||||
@ -20320,10 +20439,10 @@ packages:
|
||||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
||||
dev: true
|
||||
|
||||
/sswr@2.0.0(svelte@4.2.12):
|
||||
resolution: {integrity: sha512-mV0kkeBHcjcb0M5NqKtKVg/uTIYNlIIniyDfSGrSfxpEdM9C365jK0z55pl9K0xAkNTJi2OAOVFQpgMPUk+V0w==}
|
||||
/sswr@2.1.0(svelte@4.2.12):
|
||||
resolution: {integrity: sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ==}
|
||||
peerDependencies:
|
||||
svelte: ^4.0.0
|
||||
svelte: ^4.0.0 || ^5.0.0-next.0
|
||||
dependencies:
|
||||
svelte: 4.2.12
|
||||
swrev: 4.0.0
|
||||
|
Reference in New Issue
Block a user