feat: allow user to set max_attempt for MCP to avoid looping

This commit is contained in:
Louis 2025-08-20 12:42:54 +07:00
parent 0fc3dc6841
commit c018713676
No known key found for this signature in database
GPG Key ID: 44FA9F4D33C37DE2
9 changed files with 49 additions and 9 deletions

View File

@ -62,6 +62,7 @@ export default function AddEditAssistant({
const [showEmojiPicker, setShowEmojiPicker] = useState(false) const [showEmojiPicker, setShowEmojiPicker] = useState(false)
const emojiPickerRef = useRef<HTMLDivElement>(null) const emojiPickerRef = useRef<HTMLDivElement>(null)
const [nameError, setNameError] = useState<string | null>(null) const [nameError, setNameError] = useState<string | null>(null)
const [toolSteps, setToolSteps] = useState(20)
// Handle click outside emoji picker // Handle click outside emoji picker
useEffect(() => { useEffect(() => {
@ -90,6 +91,7 @@ export default function AddEditAssistant({
setName(initialData.name) setName(initialData.name)
setDescription(initialData.description) setDescription(initialData.description)
setInstructions(initialData.instructions) setInstructions(initialData.instructions)
setToolSteps(initialData.tool_steps ?? 20)
// Convert parameters object to arrays of keys and values // Convert parameters object to arrays of keys and values
const keys = Object.keys(initialData.parameters || {}) const keys = Object.keys(initialData.parameters || {})
const values = Object.values(initialData.parameters || {}) const values = Object.values(initialData.parameters || {})
@ -120,6 +122,7 @@ export default function AddEditAssistant({
setParamsValues(['']) setParamsValues([''])
setParamsTypes(['string']) setParamsTypes(['string'])
setNameError(null) setNameError(null)
setToolSteps(20)
} }
const handleParameterChange = ( const handleParameterChange = (
@ -216,6 +219,7 @@ export default function AddEditAssistant({
description, description,
instructions, instructions,
parameters: parameters || {}, parameters: parameters || {},
tool_steps: toolSteps,
} }
onSave(assistant) onSave(assistant)
onOpenChange(false) onOpenChange(false)
@ -323,6 +327,30 @@ export default function AddEditAssistant({
/> />
</div> </div>
<div className="space-y-2 my-4">
<div className="flex items-center justify-between">
<label className="text-sm">{t('common:settings')}</label>
</div>
<div className="flex flex-wrap gap-2">
<div className="flex items-center gap-4">
<div className="flex items-center flex-col sm:flex-row w-full gap-2">
<span className="text-sm">{t('assistants:maxToolSteps')}</span>
<Input
value={toolSteps}
type="number"
onChange={(e) => {
const newSteps = e.target.value
const stepNumber = Number(newSteps)
setToolSteps(isNaN(stepNumber) ? 20 : stepNumber)
}}
placeholder="20"
className="w-full sm:w-24"
/>
</div>
</div>
</div>
</div>
<div className="space-y-2 my-4"> <div className="space-y-2 my-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="text-sm"> <label className="text-sm">

View File

@ -254,8 +254,8 @@ export const useChat = () => {
}) })
: [] : []
// TODO: Later replaced by Agent setup? let assistantLoopSteps = 0
const followUpWithToolUse = true
while ( while (
!isCompleted && !isCompleted &&
!abortController.signal.aborted && !abortController.signal.aborted &&
@ -264,6 +264,7 @@ export const useChat = () => {
const modelConfig = activeProvider.models.find( const modelConfig = activeProvider.models.find(
(m) => m.id === selectedModel?.id (m) => m.id === selectedModel?.id
) )
assistantLoopSteps += 1
const modelSettings = modelConfig?.settings const modelSettings = modelConfig?.settings
? Object.fromEntries( ? Object.fromEntries(
@ -508,7 +509,11 @@ export const useChat = () => {
isCompleted = !toolCalls.length isCompleted = !toolCalls.length
// Do not create agent loop if there is no need for it // Do not create agent loop if there is no need for it
if (!followUpWithToolUse) availableTools = [] // Check if assistant loop steps are within limits
if (assistantLoopSteps >= (currentAssistant?.tool_steps ?? 20)) {
// Stop the assistant tool call if it exceeds the maximum steps
availableTools = []
}
} }
} catch (error) { } catch (error) {
if (!abortController.signal.aborted) { if (!abortController.signal.aborted) {

View File

@ -29,5 +29,6 @@
"save": "Speichern", "save": "Speichern",
"createNew": "Neuen Assistenten anlegen", "createNew": "Neuen Assistenten anlegen",
"personality": "Persönlichkeit", "personality": "Persönlichkeit",
"capabilities": "Fähigkeiten" "capabilities": "Fähigkeiten",
"maxToolSteps": "Maximale Werkzeugschritte"
} }

View File

@ -29,5 +29,6 @@
"save": "Save", "save": "Save",
"createNew": "Create New Assistant", "createNew": "Create New Assistant",
"personality": "Personality", "personality": "Personality",
"capabilities": "Capabilities" "capabilities": "Capabilities",
"maxToolSteps": "Max tool steps"
} }

View File

@ -29,5 +29,6 @@
"save": "Simpan", "save": "Simpan",
"createNew": "Buat Asisten Baru", "createNew": "Buat Asisten Baru",
"personality": "Kepribadian", "personality": "Kepribadian",
"capabilities": "Kemampuan" "capabilities": "Kemampuan",
"maxToolSteps": "Langkah alat maksimum"
} }

View File

@ -29,5 +29,6 @@
"save": "Lưu", "save": "Lưu",
"createNew": "Tạo Trợ lý Mới", "createNew": "Tạo Trợ lý Mới",
"personality": "Tính cách", "personality": "Tính cách",
"capabilities": "Khả năng" "capabilities": "Khả năng",
"maxToolSteps": "Bước tối đa của công cụ"
} }

View File

@ -29,5 +29,6 @@
"save": "保存", "save": "保存",
"createNew": "创建新助手", "createNew": "创建新助手",
"personality": "个性", "personality": "个性",
"capabilities": "能力" "capabilities": "能力",
"maxToolSteps": "最大工具步骤"
} }

View File

@ -29,5 +29,6 @@
"save": "儲存", "save": "儲存",
"createNew": "建立新助理", "createNew": "建立新助理",
"personality": "個性", "personality": "個性",
"capabilities": "能力" "capabilities": "能力",
"maxToolSteps": "最大工具步驟"
} }

View File

@ -54,6 +54,7 @@ type Assistant = {
description?: string description?: string
instructions: string instructions: string
parameters: Record<string, unknown> parameters: Record<string, unknown>
tool_steps?: number
} }
type TokenSpeed = { type TokenSpeed = {