mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
Added tool UI to agent
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
import { useState } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { PlusIcon, XIcon } from 'lucide-react'
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover'
|
||||
import { useSubBlockValue } from '../hooks/use-sub-block-value'
|
||||
import { getAllBlocks } from '@/blocks'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { getTool } from '@/tools'
|
||||
import { ShortInput } from './short-input'
|
||||
|
||||
interface ToolInputProps {
|
||||
blockId: string
|
||||
subBlockId: string
|
||||
}
|
||||
|
||||
// State interface - only what we need to store
|
||||
interface StoredTool {
|
||||
type: string
|
||||
title: string
|
||||
params: Record<string, string>
|
||||
}
|
||||
|
||||
// UI interface - includes display properties
|
||||
interface ToolDisplay {
|
||||
type: string
|
||||
icon: any
|
||||
title: string
|
||||
bgColor: string
|
||||
requiredParams: ToolParam[]
|
||||
}
|
||||
|
||||
interface SelectedTool {
|
||||
type: string
|
||||
icon: any
|
||||
title: string
|
||||
bgColor: string
|
||||
requiredParams?: ToolParam[]
|
||||
params?: Record<string, string>
|
||||
}
|
||||
|
||||
interface ToolParam {
|
||||
id: string
|
||||
type: string
|
||||
description?: string
|
||||
requiredForToolCall: boolean
|
||||
}
|
||||
|
||||
// Assumes the first tool in the access array is the tool to be used
|
||||
// TODO: Switch to getting tools instead of tool blocks once we switch to providers
|
||||
const getToolIdFromBlock = (blockType: string): string | undefined => {
|
||||
const block = getAllBlocks().find((block) => block.type === blockType)
|
||||
return block?.tools.access[0]
|
||||
}
|
||||
|
||||
const getRequiredToolParams = (toolId: string): ToolParam[] => {
|
||||
const tool = getTool(toolId)
|
||||
if (!tool) return []
|
||||
|
||||
return Object.entries(tool.params)
|
||||
.filter(([_, param]) => param.requiredForToolCall)
|
||||
.map(([paramId, param]) => ({
|
||||
id: paramId,
|
||||
type: param.type,
|
||||
description: param.description,
|
||||
requiredForToolCall: param.requiredForToolCall ?? false,
|
||||
}))
|
||||
}
|
||||
|
||||
export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
|
||||
const [value, setValue] = useSubBlockValue(blockId, subBlockId)
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const toolBlocks = getAllBlocks().filter(
|
||||
(block) => block.toolbar.category === 'tools'
|
||||
)
|
||||
|
||||
const selectedTools: StoredTool[] =
|
||||
Array.isArray(value) && value.length > 0 && typeof value[0] === 'object'
|
||||
? (value as unknown as StoredTool[])
|
||||
: []
|
||||
|
||||
const handleSelectTool = (toolBlock: (typeof toolBlocks)[0]) => {
|
||||
const toolId = getToolIdFromBlock(toolBlock.type)
|
||||
|
||||
// Only store essential data
|
||||
const newTool: StoredTool = {
|
||||
type: toolBlock.type,
|
||||
title: toolBlock.toolbar.title,
|
||||
params: {},
|
||||
}
|
||||
|
||||
if (!selectedTools.some((tool) => tool.type === newTool.type)) {
|
||||
setValue([...selectedTools, newTool])
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const handleRemoveTool = (toolType: string) => {
|
||||
setValue(selectedTools.filter((tool) => tool.type !== toolType))
|
||||
}
|
||||
|
||||
const handleParamChange = (
|
||||
toolType: string,
|
||||
paramId: string,
|
||||
paramValue: string
|
||||
) => {
|
||||
setValue(
|
||||
selectedTools.map((tool) => {
|
||||
if (tool.type === toolType) {
|
||||
return {
|
||||
...tool,
|
||||
params: {
|
||||
...tool.params,
|
||||
[paramId]: paramValue,
|
||||
},
|
||||
}
|
||||
}
|
||||
return tool
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const IconComponent = ({
|
||||
icon: Icon,
|
||||
className,
|
||||
}: {
|
||||
icon: any
|
||||
className?: string
|
||||
}) => {
|
||||
if (!Icon) return null
|
||||
return <Icon className={className} />
|
||||
}
|
||||
|
||||
// Helper function to get the icon component for a tool type
|
||||
const getToolIcon = (type: string) => {
|
||||
const toolBlock = toolBlocks.find((block) => block.type === type)
|
||||
return toolBlock?.toolbar.icon
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
{selectedTools.length === 0 ? (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<div className="flex h-10 w-full items-center justify-center rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer">
|
||||
<div className="flex items-center text-base text-muted-foreground/50 md:text-sm">
|
||||
<PlusIcon className="w-4 h-4 mr-2" />
|
||||
Add Tool
|
||||
</div>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0 w-[200px]" align="start">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search tools..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No tools found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{toolBlocks.map((block) => (
|
||||
<CommandItem
|
||||
key={block.type}
|
||||
onSelect={() => handleSelectTool(block)}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<div
|
||||
className="flex items-center justify-center w-6 h-6 rounded"
|
||||
style={{ backgroundColor: block.toolbar.bgColor }}
|
||||
>
|
||||
<IconComponent
|
||||
icon={block.toolbar.icon}
|
||||
className="w-4 h-4 text-white"
|
||||
/>
|
||||
</div>
|
||||
<span>{block.toolbar.title}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
) : (
|
||||
<div className="flex flex-wrap gap-2 min-h-[2.5rem] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background">
|
||||
{selectedTools.map((tool) => {
|
||||
// Get UI properties from toolBlocks for display
|
||||
const toolBlock = toolBlocks.find(
|
||||
(block) => block.type === tool.type
|
||||
)
|
||||
const toolId = getToolIdFromBlock(tool.type)
|
||||
const requiredParams = toolId ? getRequiredToolParams(toolId) : []
|
||||
|
||||
return (
|
||||
<div key={tool.type} className="group flex flex-col w-full">
|
||||
<div className="flex flex-col rounded-md border bg-card overflow-visible">
|
||||
<div className="flex items-center justify-between p-2 bg-accent/50">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="flex items-center justify-center w-5 h-5 rounded"
|
||||
style={{ backgroundColor: toolBlock?.toolbar.bgColor }}
|
||||
>
|
||||
<IconComponent
|
||||
icon={toolBlock?.toolbar.icon}
|
||||
className="w-3 h-3 text-white"
|
||||
/>
|
||||
</div>
|
||||
<span className="text-sm font-medium">{tool.title}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleRemoveTool(tool.type)}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<XIcon className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{requiredParams.length > 0 && (
|
||||
<div className="p-3 space-y-3">
|
||||
{requiredParams.map((param) => (
|
||||
<div key={param.id} className="space-y-1.5 relative">
|
||||
<div className="text-xs font-medium text-muted-foreground">
|
||||
{param.id}
|
||||
</div>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={
|
||||
param.type === 'password' ? 'password' : 'text'
|
||||
}
|
||||
value={tool.params?.[param.id] || ''}
|
||||
onChange={(e) =>
|
||||
handleParamChange(
|
||||
tool.type,
|
||||
param.id,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
placeholder={param.description}
|
||||
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 px-2 text-xs text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<PlusIcon className="w-3 h-3" />
|
||||
Add Tool
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0 w-[200px]" align="start">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search tools..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No tools found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{toolBlocks.map((block) => (
|
||||
<CommandItem
|
||||
key={block.type}
|
||||
onSelect={() => handleSelectTool(block)}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<div
|
||||
className="flex items-center justify-center w-6 h-6 rounded"
|
||||
style={{ backgroundColor: block.toolbar.bgColor }}
|
||||
>
|
||||
<IconComponent
|
||||
icon={block.toolbar.icon}
|
||||
className="w-4 h-4 text-white"
|
||||
/>
|
||||
</div>
|
||||
<span>{block.toolbar.title}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { SliderInput } from './components/slider-input'
|
||||
import { Table } from './components/table'
|
||||
import { Code } from './components/code'
|
||||
import { Switch } from './components/switch'
|
||||
import { ToolInput } from './components/tool-input'
|
||||
|
||||
interface SubBlockProps {
|
||||
blockId: string
|
||||
@@ -92,6 +93,8 @@ export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
|
||||
title={config.title}
|
||||
/>
|
||||
)
|
||||
case 'tool-input':
|
||||
return <ToolInput blockId={blockId} subBlockId={config.id} />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ export const AgentBlock: BlockConfig<ChatResponse> = {
|
||||
context: { type: 'string', required: false },
|
||||
apiKey: { type: 'string', required: true },
|
||||
responseFormat: { type: 'json', required: false },
|
||||
temperature: { type: 'number', required: false }
|
||||
temperature: { type: 'number', required: false },
|
||||
tools: { type: 'json', required: false }
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
@@ -89,12 +90,18 @@ export const AgentBlock: BlockConfig<ChatResponse> = {
|
||||
password: true,
|
||||
connectionDroppable: false
|
||||
},
|
||||
{
|
||||
id: 'tools',
|
||||
title: 'Tools',
|
||||
type: 'tool-input',
|
||||
layout: 'full'
|
||||
},
|
||||
{
|
||||
id: 'responseFormat',
|
||||
title: 'Response Format',
|
||||
type: 'code',
|
||||
layout: 'full'
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,6 @@ const toolToBlockType = Object.entries(blocks).reduce((acc, [blockType, config])
|
||||
export const getBlock = (type: string): BlockConfig | undefined =>
|
||||
blocks[type]
|
||||
|
||||
|
||||
export const getBlocksByCategory = (category: 'blocks' | 'tools'): BlockConfig[] =>
|
||||
Object.values(blocks).filter(block => block.toolbar.category === category)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export type BlockOutput =
|
||||
|
||||
export type ParamType = 'string' | 'number' | 'boolean' | 'json'
|
||||
|
||||
export type SubBlockType = 'short-input' | 'long-input' | 'dropdown' | 'slider' | 'table' | 'code' | 'switch'
|
||||
export type SubBlockType = 'short-input' | 'long-input' | 'dropdown' | 'slider' | 'table' | 'code' | 'switch' | 'tool-input'
|
||||
export type SubBlockLayout = 'full' | 'half'
|
||||
|
||||
export interface OutputConfig {
|
||||
|
||||
169
components/ui/command.tsx
Normal file
169
components/ui/command.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { type DialogProps } from '@radix-ui/react-dialog'
|
||||
import { Command as CommandPrimitive } from 'cmdk'
|
||||
import { Search } from 'lucide-react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive> & {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
const CommandDialog = ({ children, ...props }: DialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> & {
|
||||
placeholder?: string
|
||||
}
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> & {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty> & {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group> & {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('-mx-1 h-px bg-border', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item> & {
|
||||
children?: React.ReactNode
|
||||
onSelect?: () => void
|
||||
className?: string
|
||||
}
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
'ml-auto text-xs tracking-widest text-muted-foreground',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = 'CommandShortcut'
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
31
components/ui/popover.tsx
Normal file
31
components/ui/popover.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent }
|
||||
43
package-lock.json
generated
43
package-lock.json
generated
@@ -9,10 +9,10 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-alert-dialog": "^1.1.5",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-dialog": "^1.1.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"@radix-ui/react-popover": "^1.1.4",
|
||||
"@radix-ui/react-popover": "^1.1.5",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-select": "^2.1.4",
|
||||
"@radix-ui/react-slider": "^1.2.2",
|
||||
@@ -2362,15 +2362,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.4.tgz",
|
||||
"integrity": "sha512-aUACAkXx8LaFymDma+HQVji7WhvEhpFJ7+qPz17Nf4lLZqtreGOFRiNQWQmhzp7kEWg9cOyyQJpdIMUMPc/CPw==",
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.5.tgz",
|
||||
"integrity": "sha512-YXkTAftOIW2Bt3qKH8vYr6n9gCkVrvyvfiTObVjoHVTHnNj26rmvO87IKa3VgtgCjb8FAQ6qOjNViwl+9iIzlg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.3",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.4",
|
||||
"@radix-ui/react-focus-guards": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
@@ -2380,8 +2380,35 @@
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-slot": "1.1.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"aria-hidden": "^1.1.1",
|
||||
"react-remove-scroll": "^2.6.1"
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.4.tgz",
|
||||
"integrity": "sha512-XDUI0IVYVSwjMXxM6P4Dfti7AH+Y4oS/TB+sglZ/EXc7cqLwGAmp1NlMrcUjj7ks6R5WTZuWKv44FBbLpwU3sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-alert-dialog": "^1.1.5",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-dialog": "^1.1.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"@radix-ui/react-popover": "^1.1.4",
|
||||
"@radix-ui/react-popover": "^1.1.5",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-select": "^2.1.4",
|
||||
"@radix-ui/react-slider": "^1.2.2",
|
||||
|
||||
@@ -25,6 +25,7 @@ export const visionTool: ToolConfig<VisionParams, VisionResponse> = {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'API key for the selected model provider'
|
||||
},
|
||||
imageUrl: {
|
||||
|
||||
@@ -41,6 +41,7 @@ export const scrapeTool: ToolConfig<ScrapeParams, ScrapeResponse> = {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Firecrawl API key'
|
||||
},
|
||||
url: {
|
||||
|
||||
@@ -36,6 +36,7 @@ export const repoInfoTool: ToolConfig<RepoInfoParams, RepoInfoResponse> = {
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
requiredForToolCall: true,
|
||||
description: 'GitHub Personal Access Token'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -36,6 +36,7 @@ export const contactsTool: ToolConfig<ContactsParams, ContactsResponse> = {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'HubSpot API key'
|
||||
},
|
||||
email: {
|
||||
|
||||
@@ -37,6 +37,7 @@ export const opportunitiesTool: ToolConfig<OpportunityParams, OpportunityRespons
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Salesforce API key'
|
||||
},
|
||||
action: {
|
||||
|
||||
@@ -23,6 +23,7 @@ export const slackMessageTool: ToolConfig<SlackMessageParams, SlackMessageRespon
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Your Slack API token'
|
||||
},
|
||||
channel: {
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface ToolResponse {
|
||||
export interface ToolConfig<P = any, R extends ToolResponse = ToolResponse> {
|
||||
// Basic tool identification
|
||||
id: string
|
||||
name: string
|
||||
name: string
|
||||
description: string
|
||||
version: string
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface ToolConfig<P = any, R extends ToolResponse = ToolResponse> {
|
||||
params: Record<string, {
|
||||
type: string
|
||||
required?: boolean
|
||||
requiredForToolCall?: boolean
|
||||
default?: any
|
||||
description?: string
|
||||
}>
|
||||
|
||||
Reference in New Issue
Block a user