Update tool types to include custom and library tools and add web_search tool

Add web_search tool and change tool definition
This commit is contained in:
akhisud3195 2025-04-11 14:40:19 +05:30 committed by Ramnique Singh
parent 6a4579bec5
commit aad14804ea
12 changed files with 66 additions and 183 deletions

View file

@ -74,6 +74,8 @@ export async function getCopilotResponse(
const test = {
name: 'test',
description: 'test',
type: 'custom' as const,
implementation: 'mock' as const,
parameters: {
type: 'object',
properties: {},

View file

@ -49,6 +49,8 @@ export async function fetchMcpTools(projectId: string): Promise<z.infer<typeof W
const tool: z.infer<typeof WorkflowTool> = {
name: mcpTool.name,
description: mcpTool.description ?? "",
type: 'library',
implementation: 'default',
parameters: {
type: "object",
properties: props ?? {},

View file

@ -56,7 +56,18 @@ You are an helpful customer support assistant
prompt: "Hello! How can I help you?"
}
],
tools: [],
tools: [
{
"name": "web_search",
"description": "Fetch information from the web based on chat context",
"type": "library",
"parameters": {
"type": "object",
"properties": {},
},
"implementation": "default",
}
],
}
}

View file

@ -34,7 +34,15 @@ export const WorkflowPrompt = z.object({
export const WorkflowTool = z.object({
name: z.string(),
description: z.string(),
mockTool: z.boolean().default(false).optional(),
type: z.union([
z.literal('library'),
z.literal('custom'),
]).default('custom'),
implementation: z.union([
z.literal('mock'),
z.literal('default'),
z.literal('api')
]).default('mock'),
autoSubmitMockedResponse: z.boolean().default(false).optional(),
mockInstructions: z.string().optional(),
parameters: z.object({

View file

@ -67,7 +67,7 @@ export function AgentConfig({
if (!USE_TRANSFER_CONTROL_OPTIONS && agent.controlType !== 'retain') {
handleUpdate({ ...agent, controlType: 'retain' });
}
}, [USE_TRANSFER_CONTROL_OPTIONS, agent.controlType, agent, handleUpdate]);
}, [agent.controlType, agent, handleUpdate]);
const validateName = (value: string) => {
if (value.length === 0) {

View file

@ -259,7 +259,7 @@ export function ToolConfig({
}
>
<div className="flex flex-col gap-6 p-4">
{!isReadOnly && (
{!isReadOnly && tool.type !== 'library' && (
<div className="space-y-4">
<div className="space-y-2">
<label className={sectionHeaderStyles}>
@ -310,7 +310,7 @@ export function ToolConfig({
description: e.target.value
})}
placeholder="Describe what this tool does..."
disabled={isReadOnly}
disabled={isReadOnly || tool.type === 'library'}
className={textareaStyles}
autoResize
/>
@ -324,12 +324,13 @@ export function ToolConfig({
</label>
<RadioGroup
defaultValue="mock"
value={tool.mockTool ? "mock" : "api"}
defaultValue={tool.implementation}
value={tool.implementation}
onValueChange={(value) => handleUpdate({
...tool,
mockTool: value === "mock",
autoSubmitMockedResponse: value === "mock" ? true : undefined
implementation: value as "mock" | "default" | "api",
autoSubmitMockedResponse: value === "mock" ? true : undefined,
mockInstructions: value === "mock" ? tool.mockInstructions : undefined
})}
orientation="horizontal"
classNames={{
@ -346,20 +347,32 @@ export function ToolConfig({
>
Mock tool responses
</Radio>
<Radio
value="api"
classNames={{
base: "p-0 data-[selected=true]:bg-indigo-50 dark:data-[selected=true]:bg-indigo-900/50 rounded-lg transition-colors",
label: "text-base font-normal text-gray-900 dark:text-gray-100 px-3 py-1"
}}
>
Connect tool to your API
</Radio>
{tool.type === "library" ? (
<Radio
value="default"
classNames={{
base: "p-0 data-[selected=true]:bg-indigo-50 dark:data-[selected=true]:bg-indigo-900/50 rounded-lg transition-colors",
label: "text-base font-normal text-gray-900 dark:text-gray-100 px-3 py-1"
}}
>
Use default implementation
</Radio>
) : (
<Radio
value="api"
classNames={{
base: "p-0 data-[selected=true]:bg-indigo-50 dark:data-[selected=true]:bg-indigo-900/50 rounded-lg transition-colors",
label: "text-base font-normal text-gray-900 dark:text-gray-100 px-3 py-1"
}}
>
Connect tool to your API
</Radio>
)}
</RadioGroup>
</div>
)}
{tool.mockTool && (
{tool.implementation === "mock" && (
<div className={`space-y-4 ${dividerStyles} pt-6`}>
<div className="space-y-4">
<label className={sectionHeaderStyles}>
@ -411,12 +424,12 @@ export function ToolConfig({
handleUpdate={handleParamUpdate}
handleDelete={handleParamDelete}
handleRename={handleParamRename}
readOnly={isReadOnly}
readOnly={isReadOnly || tool.type === 'library'}
/>
))}
</div>
{!isReadOnly && (
{!isReadOnly && tool.type !== 'library' && (
<div className="pl-3">
<Button
variant="primary"
@ -434,6 +447,8 @@ export function ToolConfig({
handleUpdate({
...tool,
type: 'custom',
implementation: 'mock',
parameters: {
type: 'object',
properties: newProperties,

View file

@ -210,7 +210,10 @@ export function EntityList({
<Button
variant="secondary"
size="sm"
onClick={() => onAddTool({})}
onClick={() => onAddTool({
type: 'custom',
implementation: 'mock'
})}
className={`group ${buttonClasses}`}
showHoverContent={true}
hoverContent="Add Tool"

View file

@ -290,10 +290,11 @@ function reducer(state: State, action: Action): State {
name: newToolName,
description: "",
parameters: {
type: "object",
type: 'object',
properties: {},
},
mockTool: true,
type: 'custom',
implementation: 'mock',
autoSubmitMockedResponse: true,
...action.tool
});

View file

@ -1,8 +1,6 @@
'use client';
import { Project } from "@/app/lib/types/project_types";
import { useEffect, useState, useRef } from "react";
import { z } from "zod";
import { createProject, createProjectFromPrompt } from "@/app/actions/project_actions";
import { useRouter } from 'next/navigation';
import clsx from 'clsx';

View file

@ -1,7 +1,6 @@
import { Project } from "@/app/lib/types/project_types";
import { z } from "zod";
import { ProjectList } from "./project-list";
import { SectionHeading } from "@/components/ui/section-heading";
import { HorizontalDivider } from "@/components/ui/horizontal-divider";
import clsx from 'clsx';
import { XMarkIcon } from "@heroicons/react/24/outline";

View file

@ -1,101 +0,0 @@
'use client';
import clsx from 'clsx';
import { CheckIcon } from "lucide-react";
import { useState } from "react";
import React from "react";
import { WorkflowTemplate } from "@/app/lib/types/workflow_types";
import { z } from "zod";
import { tokens } from "@/app/styles/design-tokens";
interface TemplateCardProps {
templateKey: string;
template: z.infer<typeof WorkflowTemplate> | string;
onSelect: (templateKey: string) => void;
selected: boolean;
type?: "template" | "prompt";
}
export function TemplateCard({
templateKey,
template,
onSelect,
selected,
type = "template"
}: TemplateCardProps) {
const [isExpanded, setIsExpanded] = useState(false);
const name = typeof template === "string" ? templateKey : template.name;
const description = typeof template === "string" ? template : template.description;
const textRef = React.useRef<HTMLDivElement>(null);
const [needsExpansion, setNeedsExpansion] = useState(false);
React.useEffect(() => {
if (textRef.current) {
const needsButton = textRef.current.scrollHeight > textRef.current.clientHeight;
setNeedsExpansion(needsButton);
}
}, [description]);
return (
<div
onClick={() => onSelect(templateKey)}
className={clsx(
"w-full text-left cursor-pointer",
"p-4",
tokens.radius.lg,
tokens.transitions.default,
tokens.shadows.sm,
"border",
selected ? [
"border-indigo-600 dark:border-indigo-400",
"bg-indigo-50/50 dark:bg-indigo-500/10",
] : [
tokens.colors.light.border,
tokens.colors.dark.border,
tokens.colors.light.surface,
tokens.colors.dark.surface,
"hover:border-indigo-600/30 dark:hover:border-indigo-400/30",
"hover:bg-indigo-50/30 dark:hover:bg-indigo-500/5",
"transform hover:scale-[1.01]",
tokens.shadows.hover,
],
tokens.focus.default,
tokens.focus.dark
)}
>
<div className="flex items-start justify-between gap-4">
<div className="flex-1 space-y-2">
<h3 className={clsx(
tokens.typography.sizes.base,
tokens.typography.weights.medium,
tokens.colors.light.text.primary,
tokens.colors.dark.text.primary
)}>
{name}
</h3>
<p className={clsx(
tokens.typography.sizes.sm,
tokens.colors.light.text.secondary,
tokens.colors.dark.text.secondary
)}>
{description}
</p>
</div>
<div className={clsx(
"w-5 h-5 rounded-full border-2",
tokens.transitions.default,
selected ? [
"border-indigo-600 dark:border-indigo-400",
"bg-indigo-600 dark:bg-indigo-400",
] : [
"border-gray-300 dark:border-gray-600",
]
)}>
{selected && (
<CheckIcon className="w-4 h-4 text-white" />
)}
</div>
</div>
</div>
);
}

View file

@ -1,55 +0,0 @@
import { templates, starting_copilot_prompts } from "@/app/lib/project_templates";
import { TemplateCard } from "./template-card";
import { WorkflowTemplate } from "@/types/workflow_types";
import { z } from "zod";
// Use the existing template type but make id optional
type Template = z.infer<typeof WorkflowTemplate> & {
id?: string;
prompt?: string;
};
type TemplateCardsListProps = {
selectedCard: 'custom' | Template;
onSelectCard: (template: Template) => void;
};
export function TemplateCardsList({ selectedCard, onSelectCard }: TemplateCardsListProps) {
return (
<div className="grid grid-cols-2 gap-4">
{Object.entries(templates).map(([id, template]) => (
<TemplateCard
key={id}
templateKey={id}
template={template} // Remove the type assertion
selected={selectedCard !== 'custom' && selectedCard.id === id}
onSelect={() => onSelectCard({ ...template, id })}
/>
))}
{Object.entries(starting_copilot_prompts).map(([name, prompt]) => {
// Create a template-compatible object
const promptTemplate: Template = {
name,
description: prompt,
prompt,
id: name.toLowerCase(),
agents: [], // Required by WorkflowTemplate
prompts: [], // Required by WorkflowTemplate
tools: [], // Required by WorkflowTemplate
startAgent: '' // Required by WorkflowTemplate
};
return (
<TemplateCard
key={name}
templateKey={name.toLowerCase()}
template={promptTemplate}
selected={selectedCard !== 'custom' && selectedCard.id === name.toLowerCase()}
onSelect={() => onSelectCard(promptTemplate)}
/>
);
})}
</div>
);
}