diff --git a/channels/webui.py b/channels/webui.py index e4c806e6..7fe5d471 100644 --- a/channels/webui.py +++ b/channels/webui.py @@ -49,6 +49,7 @@ "upload", "theming", "modal_settings", + "new_menu_options", "storage_editor", "responsive", "init" diff --git a/channels/webui/static/js/new_menu_options.js b/channels/webui/static/js/new_menu_options.js new file mode 100644 index 00000000..6c9a6cbb --- /dev/null +++ b/channels/webui/static/js/new_menu_options.js @@ -0,0 +1,22 @@ +// ============================================================================= +// Agent Menu Options +// ============================================================================= + +// Defines metadata for agent-related configuration options. +// Loaded after modal_settings.js to extend FIELD_DESCRIPTIONS. +const AGENT_MENU_OPTIONS = [ + { + key: 'model.agent_replan_on_error', + label: 'Replan on error', + description: 'When enabled, the agent will restart its planning loop when a tool call returns an error, prompting it to try a different strategy instead of continuing with a failed result.', + type: 'boolean', + default: false + } +]; + +// Extend field descriptions for agent options so they appear in the settings UI +for (const option of AGENT_MENU_OPTIONS) { + if (option.description) { + FIELD_DESCRIPTIONS[option.key] = option.description; + } +} diff --git a/core/config.py b/core/config.py index 5e680387..0d49a273 100644 --- a/core/config.py +++ b/core/config.py @@ -16,7 +16,8 @@ "model": { "name": "MODEL_HERE", "temperature": 0.2, - "use_tools": True + "use_tools": True, + "agent_replan_on_error": False }, "channels": { "enabled": ["cli", "webui"], diff --git a/core/toolcalls.py b/core/toolcalls.py index de7f95ab..1eb6e72d 100644 --- a/core/toolcalls.py +++ b/core/toolcalls.py @@ -55,6 +55,8 @@ async def process(self, tool_calls, initial_content=""): await self.channel.context.chat.add(assistant_message) # Execute each tool and add their responses + had_tool_error = False + for tool_call_dict in repaired_tool_calls: tool_name = tool_call_dict['function']['name'] tool_args = json_repair.loads(tool_call_dict['function']['arguments']) @@ -97,6 +99,7 @@ async def process(self, tool_calls, initial_content=""): } except Exception as e: core.log("toolcall", f"error: {str(e)}") + had_tool_error = True tool_response = { "role": "tool", "tool_call_id": tool_call_dict['id'], @@ -116,13 +119,23 @@ async def process(self, tool_calls, initial_content=""): # Build context and stream response context = await self.channel.context.get(system_prompt=False) + + replan_on_error = core.config.get("model", {}).get("agent_replan_on_error", False) + if had_tool_error and replan_on_error: + system_content = ( + "One or more tool calls returned an error. " + "Please replan your approach and try a different strategy to achieve the goal." + ) + else: + system_content = ( + "If the tool response provides sufficient answers, " + "explain the results to the user. If not, call another tool." + ) + prompt = [ { "role": "system", - "content": ( - "If the tool response provides sufficient answers, " - "explain the results to the user. If not, call another tool." - ) + "content": system_content } ] + context