Skip to content

feat(agent): Add tool confirmation/consent flow for sensitive operations #248

@mmogr

Description

@mmogr

Summary

Tools currently execute automatically when the LLM requests them. The only gate is the enable/disable allowlist in ToolRegistry. There's no mechanism for users to review and approve individual tool calls before execution — particularly important for tools that write data, call external APIs, or execute commands.

Motivation

  • Security: MCP tools from third-party servers can perform destructive operations
  • Safety: Users should be able to inspect tool arguments before execution (e.g., "Are you sure you want to delete this file?")
  • Trust building: Users new to agentic AI want to see what tools are doing before granting autonomy
  • Precedent: vscode-copilot-chat requires explicit user confirmation for certain tool categories via a confirmation field in tool metadata

Proposed Solution

Phase 1: Tool metadata extension

Add a requiresConfirmation field to the tool registration system:

// types.ts
export interface RegisteredTool {
  definition: ToolDefinition;
  executor: ToolExecutor;
  source: ToolSource;
  requiresConfirmation: boolean;  // NEW
  confirmationMessage?: string;   // NEW — optional custom message
}

Default values:

  • Built-in tools: false (trusted)
  • MCP read-only tools: false
  • MCP write/execute tools: true (conservative default)
  • User can override per-tool in settings

Phase 2: Intervention-based pause in agentic loop

The deep research loop already has an InterventionRef pattern for human-in-the-loop control. Apply the same pattern to runAgenticLoop.ts:

// Before executing each tool:
if (registeredTool.requiresConfirmation) {
  // Emit a confirmation request event
  onToolConfirmationNeeded({
    toolCall,
    toolName: registeredTool.definition.function.name,
    args: parsedArgs,
    message: registeredTool.confirmationMessage,
  });
  
  // Wait for user response (approve/deny/approve-all)
  const decision = await waitForConfirmation(toolCall.id);
  
  if (decision === 'deny') {
    result = { success: false, error: 'User denied tool execution' };
    continue;
  }
  if (decision === 'approve-all') {
    // Disable confirmation for this tool for rest of session
    registeredTool.requiresConfirmation = false;
  }
}

Phase 3: Confirmation UI component

A modal/inline component that shows:

  • Tool name and description
  • Formatted arguments (syntax-highlighted JSON)
  • "Allow", "Deny", "Allow all from this tool" buttons
  • Auto-deny timeout (e.g., 60 seconds) so the loop doesn't hang forever

Files to Modify

File Change
src/services/tools/types.ts Add requiresConfirmation, confirmationMessage to RegisteredTool
src/services/tools/registry.ts Support confirmation field in registration, add isConfirmationRequired()
src/services/tools/mcpIntegration.ts Set default confirmation policy for MCP tools
src/hooks/useGglibRuntime/runAgenticLoop.ts Add confirmation check before tool execution
src/components/ New ToolConfirmationDialog component
src/contexts/ or src/hooks/ Confirmation state management

Acceptance Criteria

  • Tools can be registered with requiresConfirmation: true
  • Agentic loop pauses and requests user confirmation before executing flagged tools
  • User can "Allow", "Deny", or "Allow all" for each confirmation
  • MCP tools default to requiring confirmation (conservative security posture)
  • Built-in tools default to not requiring confirmation
  • Confirmation UI shows tool name, description, and formatted arguments
  • Auto-deny timeout prevents the loop from hanging indefinitely
  • "Allow all" persists for the current session (not across restarts)
  • Tool denial is reported back to the LLM as an error result so it can adapt

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions