Python: Integrate tool approval into the harness (#6522)
* Integrate auto tool-approval feature into harness * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Rename disable_tool_approval to disable_tool_auto_approval Addresses PR review feedback that the parameter name was unclear. The flag toggles the auto/standing tool-approval middleware. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -18,6 +18,7 @@ from a chat client.
|
||||
| MemoryContextProvider | File-based durable memory (when `memory_store` provided) |
|
||||
| SkillsProvider | File-based skill discovery and progressive loading |
|
||||
| Shell tool | Shell command execution + environment probing (when `shell_executor` provided) |
|
||||
| Tool approval | "Don't ask again" standing rules + heuristic auto-approval (enabled by default) |
|
||||
| OpenTelemetry | Built-in observability |
|
||||
|
||||
Each feature can be disabled or customized via keyword arguments.
|
||||
|
||||
@@ -182,6 +182,8 @@ class FallbackToolFormatter(ToolCallFormatter):
|
||||
args_dict = json.loads(call.arguments)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
return None
|
||||
if not isinstance(args_dict, dict):
|
||||
return None
|
||||
elif isinstance(call.arguments, dict):
|
||||
args_dict = call.arguments
|
||||
else:
|
||||
|
||||
@@ -84,23 +84,38 @@ class ToolApprovalObserver(ConsoleObserver):
|
||||
tool_name = self._format_tool_name(request)
|
||||
prompt = f"🔐 Tool approval: {tool_name}"
|
||||
|
||||
# TODO(westey-m): Add "Always approve" options when the framework supports
|
||||
# CreateAlwaysApproveToolResponse / CreateAlwaysApproveToolWithArgumentsResponse.
|
||||
choices = [
|
||||
"Approve this call",
|
||||
"Deny",
|
||||
]
|
||||
approve_once = "Approve this call"
|
||||
always_tool = "Always approve this tool (any arguments)"
|
||||
always_tool_args = "Always approve this tool with these arguments"
|
||||
deny = "Deny"
|
||||
choices = [approve_once, always_tool, always_tool_args, deny]
|
||||
|
||||
async def continuation(
|
||||
selection: str,
|
||||
ux: IUXStateDriver,
|
||||
) -> Message | None:
|
||||
from agent_framework import Message
|
||||
from agent_framework import (
|
||||
Message,
|
||||
create_always_approve_tool_response,
|
||||
create_always_approve_tool_with_arguments_response,
|
||||
)
|
||||
|
||||
if selection == "Deny":
|
||||
if selection == deny:
|
||||
response_content = request.to_function_approval_response(approved=False)
|
||||
action_label = "❌ Denied"
|
||||
color = "red"
|
||||
elif selection == always_tool:
|
||||
response_content = create_always_approve_tool_response(
|
||||
request, reason="User chose to always approve this tool"
|
||||
)
|
||||
action_label = "✅ Always approved (any args)"
|
||||
color = "green"
|
||||
elif selection == always_tool_args:
|
||||
response_content = create_always_approve_tool_with_arguments_response(
|
||||
request, reason="User chose to always approve this tool with these arguments"
|
||||
)
|
||||
action_label = "✅ Always approved (these args)"
|
||||
color = "green"
|
||||
else:
|
||||
response_content = request.to_function_approval_response(approved=True)
|
||||
action_label = "✅ Approved"
|
||||
|
||||
Reference in New Issue
Block a user