Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions frontend/src/components/agent/AdvancedTab.tsx
Original file line number Diff line number Diff line change
@@ -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<AgentFormValues>;
}

export function AdvancedTab({ form }: AdvancedTabProps) {
return (
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Context Settings</CardTitle>
<CardDescription>Configure how the agent handles conversation history and context</CardDescription>
</CardHeader>
<CardContent className="grid gap-6 sm:grid-cols-2">
<FormField
control={form.control}
name="context_strategy"
render={({ field }) => (
<FormItem>
<FormLabel>Context Strategy</FormLabel>
<Select onValueChange={field.onChange} value={field.value || ''}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select strategy" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="None">None</SelectItem>
<SelectItem value="Summarize">Summarize</SelectItem>
<SelectItem value="FIFO">FIFO</SelectItem>
</SelectContent>
</Select>
<FormDescription>
How to handle conversation history when it exceeds the limit. 'Summarize' compresses old messages, 'FIFO' drops them.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="summary_ratio"
render={({ field }) => (
<FormItem>
<FormLabel>Summary Ratio</FormLabel>
<FormControl>
<Input
type="text"
placeholder="0.7"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => {
const value = e.target.value;
if (value === '') {
field.onChange(undefined);
} else {
const numValue = parseFloat(value);
if (!isNaN(numValue)) {
field.onChange(numValue);
}
}
}}
/>
</FormControl>
<FormDescription>
Ratio of history to summarize effectively. 0.7 means 70% of oldest messages.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="history_limit"
render={({ field }) => (
<FormItem>
<FormLabel>History Limit</FormLabel>
<FormControl>
<Input
type="number"
placeholder="50"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => {
const value = e.target.value;
if (value === '') {
field.onChange(undefined);
} else {
const numValue = parseInt(value, 10);
if (!isNaN(numValue)) {
field.onChange(numValue);
}
}
}}
/>
</FormControl>
<FormDescription>
Maximum number of messages to keep in active context before applying strategy.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="max_knowledge_tokens"
render={({ field }) => (
<FormItem>
<FormLabel>Max Knowledge Tokens</FormLabel>
<FormControl>
<Input
type="number"
placeholder="2000"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => {
const value = e.target.value;
if (value === '') {
field.onChange(undefined);
} else {
const numValue = parseInt(value, 10);
if (!isNaN(numValue)) {
field.onChange(numValue);
}
}
}}
/>
</FormControl>
<FormDescription>
Maximum tokens to use for injected knowledge context.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="max_turns"
render={({ field }) => (
<FormItem>
<FormLabel>Max Turns</FormLabel>
<FormControl>
<Input
type="number"
placeholder="10"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => {
const value = e.target.value;
if (value === '') {
field.onChange(undefined);
} else {
const numValue = parseInt(value, 10);
if (!isNaN(numValue)) {
field.onChange(numValue);
}
}
}}
/>
</FormControl>
<FormDescription>
Maximum consecutive turns/steps the agent can take in a single run.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="enable_conversation_data"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4 sm:col-span-2">
<div className="space-y-0.5">
<FormLabel className="text-base">Allow Conversation Data Management</FormLabel>
<FormDescription>
If enabled, the agent can store key-value pairs in the conversation context.
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value ?? false}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>

<FormField
control={form.control}
name="autonaming_of_conversation_title"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4 sm:col-span-2">
<div className="space-y-0.5">
<FormLabel className="text-base">Autonaming of Conversation Title</FormLabel>
<FormDescription>
If enabled, the conversation title will be automatically updated based on the initial context.
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value ?? false}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
</CardContent>
</Card>
</div>
);
}
22 changes: 22 additions & 0 deletions frontend/src/components/agent/GeneralTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -179,6 +180,27 @@ export function GeneralTab({ form, providers, models, watchProvider, optimizingP
</FormItem>
)}
/>

<FormField
control={form.control}
name="enable_prompt_caching"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4 sm:col-span-2">
<div className="space-y-0.5">
<FormLabel className="text-base">Enable Prompt Caching</FormLabel>
<FormDescription>
Enable prompt caching to cache repeated prompt content and reduce token costs. Only works with supported providers (OpenAI, Anthropic, Bedrock, Deepseek).
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value ?? false}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
</CardContent>
</Card>

Expand Down
34 changes: 25 additions & 9 deletions frontend/src/components/agent/ToolsTab.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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;
Expand All @@ -26,6 +27,7 @@ export function ToolsTab({
toolTypes,
onAddTools,
onRemoveTool,
onEditTool,
mcpServers = [],
onAddMCP,
onRemoveMCP,
Expand Down Expand Up @@ -136,14 +138,28 @@ export function ToolsTab({
<p className="text-xs text-muted-foreground">{tool.description}</p>
)}
</div>
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => onRemoveTool(tool.name)}
>
<Trash2 className="w-4 h-4" />
</Button>
<div className="flex items-center gap-1">
{onEditTool && (
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => onEditTool(tool.name)}
title="Edit tool"
>
<Edit className="w-4 h-4" />
</Button>
)}
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => onRemoveTool(tool.name)}
title="Remove tool"
>
<Trash2 className="w-4 h-4" />
</Button>
</div>
</div>
);
})}
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/components/agent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof agentFormSchema>;
Expand Down
Loading
Loading