diff --git a/frontend/src/components/agent/AdvancedTab.tsx b/frontend/src/components/agent/AdvancedTab.tsx new file mode 100644 index 00000000..b053bd9a --- /dev/null +++ b/frontend/src/components/agent/AdvancedTab.tsx @@ -0,0 +1,225 @@ +import { FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage } from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Switch } from '@/components/ui/switch'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { UseFormReturn } from 'react-hook-form'; +import type { AgentFormValues } from './types'; + +interface AdvancedTabProps { + form: UseFormReturn; +} + +export function AdvancedTab({ form }: AdvancedTabProps) { + return ( +
+ + + Context Settings + Configure how the agent handles conversation history and context + + + ( + + Context Strategy + + + How to handle conversation history when it exceeds the limit. 'Summarize' compresses old messages, 'FIFO' drops them. + + + + )} + /> + + ( + + Summary Ratio + + { + const value = e.target.value; + if (value === '') { + field.onChange(undefined); + } else { + const numValue = parseFloat(value); + if (!isNaN(numValue)) { + field.onChange(numValue); + } + } + }} + /> + + + Ratio of history to summarize effectively. 0.7 means 70% of oldest messages. + + + + )} + /> + + ( + + History Limit + + { + const value = e.target.value; + if (value === '') { + field.onChange(undefined); + } else { + const numValue = parseInt(value, 10); + if (!isNaN(numValue)) { + field.onChange(numValue); + } + } + }} + /> + + + Maximum number of messages to keep in active context before applying strategy. + + + + )} + /> + + ( + + Max Knowledge Tokens + + { + const value = e.target.value; + if (value === '') { + field.onChange(undefined); + } else { + const numValue = parseInt(value, 10); + if (!isNaN(numValue)) { + field.onChange(numValue); + } + } + }} + /> + + + Maximum tokens to use for injected knowledge context. + + + + )} + /> + + ( + + Max Turns + + { + const value = e.target.value; + if (value === '') { + field.onChange(undefined); + } else { + const numValue = parseInt(value, 10); + if (!isNaN(numValue)) { + field.onChange(numValue); + } + } + }} + /> + + + Maximum consecutive turns/steps the agent can take in a single run. + + + + )} + /> + + ( + +
+ Allow Conversation Data Management + + If enabled, the agent can store key-value pairs in the conversation context. + +
+ + + +
+ )} + /> + + ( + +
+ Autonaming of Conversation Title + + If enabled, the conversation title will be automatically updated based on the initial context. + +
+ + + +
+ )} + /> +
+
+
+ ); +} diff --git a/frontend/src/components/agent/GeneralTab.tsx b/frontend/src/components/agent/GeneralTab.tsx index 355b7e47..11331ed0 100644 --- a/frontend/src/components/agent/GeneralTab.tsx +++ b/frontend/src/components/agent/GeneralTab.tsx @@ -3,6 +3,7 @@ import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Slider } from '@/components/ui/slider'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Switch } from '@/components/ui/switch'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'; import { UseFormReturn } from 'react-hook-form'; @@ -179,6 +180,27 @@ export function GeneralTab({ form, providers, models, watchProvider, optimizingP )} /> + + ( + +
+ Enable Prompt Caching + + Enable prompt caching to cache repeated prompt content and reduce token costs. Only works with supported providers (OpenAI, Anthropic, Bedrock, Deepseek). + +
+ + + +
+ )} + /> diff --git a/frontend/src/components/agent/ToolsTab.tsx b/frontend/src/components/agent/ToolsTab.tsx index b19a5513..310cc7b2 100644 --- a/frontend/src/components/agent/ToolsTab.tsx +++ b/frontend/src/components/agent/ToolsTab.tsx @@ -1,4 +1,4 @@ -import { Plus, Server, Plug, Trash2, RefreshCw } from 'lucide-react'; +import { Plus, Server, Plug, Trash2, RefreshCw, Edit } from 'lucide-react'; import { Link } from 'react-router-dom'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; @@ -12,6 +12,7 @@ interface ToolsTabProps { toolTypes: AgentToolType[]; onAddTools: () => void; onRemoveTool: (toolId: string) => void; + onEditTool?: (toolId: string) => void; // MCP Server props mcpServers?: MCPServerRef[]; onAddMCP?: () => void; @@ -26,6 +27,7 @@ export function ToolsTab({ toolTypes, onAddTools, onRemoveTool, + onEditTool, mcpServers = [], onAddMCP, onRemoveMCP, @@ -136,14 +138,28 @@ export function ToolsTab({

{tool.description}

)} - +
+ {onEditTool && ( + + )} + +
); })} diff --git a/frontend/src/components/agent/types.ts b/frontend/src/components/agent/types.ts index 3ba479b5..cdb98cc0 100644 --- a/frontend/src/components/agent/types.ts +++ b/frontend/src/components/agent/types.ts @@ -13,6 +13,14 @@ export const agentFormSchema = z.object({ enable_multi_run: z.boolean(), description: z.string().optional(), instructions: z.string(), + enable_prompt_caching: z.boolean().optional(), + context_strategy: z.string().optional(), + summary_ratio: z.number().optional(), + history_limit: z.number().optional(), + max_knowledge_tokens: z.number().optional(), + max_turns: z.number().optional(), + enable_conversation_data: z.boolean().optional(), + autonaming_of_conversation_title: z.boolean().optional(), }); export type AgentFormValues = z.infer; diff --git a/frontend/src/components/tools/HttpHeaderCard.tsx b/frontend/src/components/tools/HttpHeaderCard.tsx new file mode 100644 index 00000000..4afba625 --- /dev/null +++ b/frontend/src/components/tools/HttpHeaderCard.tsx @@ -0,0 +1,69 @@ +import { Trash2 } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Card, CardContent } from '@/components/ui/card'; +import { Label } from '@/components/ui/label'; + +export type HttpHeaderData = { + key: string; + value: string; +}; + +interface HttpHeaderCardProps { + header: HttpHeaderData; + index: number; + onChange: (index: number, data: Partial) => void; + onDelete: (index: number) => void; +} + +export function HttpHeaderCard({ + header, + index, + onChange, + onDelete, +}: HttpHeaderCardProps) { + const handleChange = (field: keyof HttpHeaderData, value: string) => { + onChange(index, { [field]: value }); + }; + + return ( + + +
+

Header {index + 1}

+ +
+ +
+
+ + handleChange('key', e.target.value)} + placeholder="e.g., Authorization" + /> +
+ +
+ + handleChange('value', e.target.value)} + placeholder="e.g., Bearer token123" + /> +
+
+
+
+ ); +} diff --git a/frontend/src/components/tools/ParameterCard.tsx b/frontend/src/components/tools/ParameterCard.tsx new file mode 100644 index 00000000..be64f232 --- /dev/null +++ b/frontend/src/components/tools/ParameterCard.tsx @@ -0,0 +1,161 @@ +import { Trash2 } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Textarea } from '@/components/ui/textarea'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Checkbox } from '@/components/ui/checkbox'; +import { Card, CardContent } from '@/components/ui/card'; +import { Label } from '@/components/ui/label'; + +export type ParameterData = { + label: string; + fieldname: string; + type: 'string' | 'integer' | 'number' | 'float' | 'boolean' | 'object' | 'array'; + required: boolean; + description?: string; + options?: string; + child_table_name?: string; +}; + +interface ParameterCardProps { + parameter: ParameterData; + index: number; + onChange: (index: number, data: Partial) => void; + onDelete: (index: number) => void; +} + +const parameterTypes = [ + 'string', + 'integer', + 'number', + 'float', + 'boolean', + 'object', + 'array', +] as const; + +export function ParameterCard({ + parameter, + index, + onChange, + onDelete, +}: ParameterCardProps) { + const handleChange = (field: keyof ParameterData, value: any) => { + onChange(index, { [field]: value }); + }; + + return ( + + +
+

Parameter {index + 1}

+ +
+ +
+
+ + handleChange('label', e.target.value)} + placeholder="e.g., Document ID" + /> +
+ +
+ + handleChange('fieldname', e.target.value)} + placeholder="e.g., document_id" + /> +
+
+ +
+
+ + +
+ +
+ + handleChange('child_table_name', e.target.value)} + placeholder="Optional" + /> +
+
+ +
+ +