chatbot-ui/components/sidebar/items/tools/tool-item.tsx

167 lines
5.1 KiB
TypeScript

import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { TextareaAutosize } from "@/components/ui/textarea-autosize"
import { TOOL_DESCRIPTION_MAX, TOOL_NAME_MAX } from "@/db/limits"
import { validateOpenAPI } from "@/lib/openapi-conversion"
import { Tables } from "@/supabase/types"
import { IconBolt } from "@tabler/icons-react"
import { FC, useState } from "react"
import { SidebarItem } from "../all/sidebar-display-item"
interface ToolItemProps {
tool: Tables<"tools">
}
export const ToolItem: FC<ToolItemProps> = ({ tool }) => {
const [name, setName] = useState(tool.name)
const [isTyping, setIsTyping] = useState(false)
const [description, setDescription] = useState(tool.description)
const [url, setUrl] = useState(tool.url)
const [customHeaders, setCustomHeaders] = useState(
tool.custom_headers as string
)
const [schema, setSchema] = useState(tool.schema as string)
const [schemaError, setSchemaError] = useState("")
return (
<SidebarItem
item={tool}
isTyping={isTyping}
contentType="tools"
icon={<IconBolt size={30} />}
updateState={{
name,
description,
url,
custom_headers: customHeaders,
schema
}}
renderInputs={() => (
<>
<div className="space-y-1">
<Label>{t("side.name")}</Label>
<Input
placeholder="Tool name..."
value={name}
onChange={e => setName(e.target.value)}
maxLength={TOOL_NAME_MAX}
/>
</div>
<div className="space-y-1">
<Label>{t("side.description")}</Label>
<Input
placeholder={t("side.toolDescriptionPlaceholder")}
value={description}
onChange={e => setDescription(e.target.value)}
maxLength={TOOL_DESCRIPTION_MAX}
/>
</div>
{/* <div className="space-y-1">
<Label>URL</Label>
<Input
placeholder="Tool url..."
value={url}
onChange={e => setUrl(e.target.value)}
/>
</div> */}
{/* <div className="space-y-3 pt-4 pb-3">
<div className="space-x-2 flex items-center">
<Checkbox />
<Label>Web Browsing</Label>
</div>
<div className="space-x-2 flex items-center">
<Checkbox />
<Label>Image Generation</Label>
</div>
<div className="space-x-2 flex items-center">
<Checkbox />
<Label>Code Interpreter</Label>
</div>
</div> */}
<div className="space-y-1">
<Label>{t("side.customHeadersLabel")}</Label>
<TextareaAutosize
placeholder={`{"X-api-key": "1234567890"}`}
value={customHeaders}
onValueChange={setCustomHeaders}
minRows={1}
/>
</div>
<div className="space-y-1">
<Label>{t("side.schemaLabel")}</Label>
<TextareaAutosize
placeholder={`{
"openapi": "3.1.0",
"info": {
"title": "Get weather data",
"description": "Retrieves current weather data for a location.",
"version": "v1.0.0"
},
"servers": [
{
"url": "https://weather.example.com"
}
],
"paths": {
"/location": {
"get": {
"description": "Get temperature for a specific location",
"operationId": "GetCurrentWeather",
"parameters": [
{
"name": "location",
"in": "query",
"description": "The city and state to retrieve the weather for",
"required": true,
"schema": {
"type": "string"
}
}
],
"deprecated": false
}
}
},
"components": {
"schemas": {}
}
}`}
value={schema}
onValueChange={value => {
setSchema(value)
try {
const parsedSchema = JSON.parse(value)
validateOpenAPI(parsedSchema)
.then(() => setSchemaError("")) // Clear error if validation is successful
.catch(error => setSchemaError(error.message)) // Set specific validation error message
} catch (error) {
setSchemaError("Invalid JSON format") // Set error for invalid JSON format
}
}}
minRows={15}
/>
<div className="text-xs text-red-500">{schemaError}</div>
</div>
</>
)}
/>
)
}