Skip to content

sub(#248) Phase 1: Tool metadata extensions and loop pause mechanism #269

@mmogr

Description

@mmogr

Parent: #248 — Tool confirmation/consent flow

Goal

Extend the tool metadata model with risk level annotations and a requiresConfirmation flag, and implement the agentic loop pause/resume mechanism.

Background

Currently all tools execute immediately without user consent. High-impact tools (file writes, shell commands, API calls with side effects) should optionally require user confirmation before executing.

Implementation

1. Extend ToolDefinition metadata

// src/services/tools/types.ts
export interface ToolMetadata {
  /** Risk level for UI display and confirmation logic */
  riskLevel: 'safe' | 'moderate' | 'dangerous';
  
  /** Whether to pause before executing and ask user */
  requiresConfirmation: boolean;
  
  /** Human-readable description of what this tool does */
  impactDescription?: string;
  
  /** Category for grouping in UI */
  category?: string;
}

export interface ToolDefinition {
  name: string;
  description: string;
  parameters: JSONSchema;
  handler: ToolHandler;
  source: ToolSource;
  metadata?: ToolMetadata; // NEW
}

2. Default risk levels

const DEFAULT_RISK_LEVELS: Record<string, ToolMetadata> = {
  'web_search': { riskLevel: 'safe', requiresConfirmation: false },
  'read_file': { riskLevel: 'safe', requiresConfirmation: false },
  'write_file': { riskLevel: 'moderate', requiresConfirmation: true },
  'run_command': { riskLevel: 'dangerous', requiresConfirmation: true },
  'delete_file': { riskLevel: 'dangerous', requiresConfirmation: true },
};

// MCP tools default to 'moderate' + requiresConfirmation: true
// Users can override per-tool in settings

3. Agentic loop pause/resume mechanism

In runAgenticLoop.ts, before executing a tool that requires confirmation:

for (const toolCall of toolCalls) {
  const tool = registry.get(toolCall.function.name);
  
  if (tool?.metadata?.requiresConfirmation) {
    // Emit confirmation request event to UI
    const approved = await requestToolConfirmation(toolCall, tool.metadata);
    if (!approved) {
      // Add "tool was denied by user" message to conversation
      apiMessages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: 'Tool execution denied by user.',
      });
      continue;
    }
  }
  
  // Execute tool normally
  const result = await executeToolCall(toolCall);
}

4. Add confirmation callback to loop config

interface AgenticLoopConfig {
  // ...existing config...
  onToolConfirmationRequired?: (
    toolCall: ToolCall,
    metadata: ToolMetadata,
  ) => Promise<boolean>;  // true = approve, false = deny
}

Files to Create/Modify

File Change
src/services/tools/types.ts Add ToolMetadata interface with risk levels
src/services/tools/registry.ts Support metadata on registration, expose via get()
src/services/tools/builtinTools.ts Add default risk levels to builtin tools
src/services/tools/mcpIntegration.ts Default MCP tools to moderate risk
src/hooks/useGglibRuntime/runAgenticLoop.ts Add confirmation check before tool execution

Acceptance Criteria

  • ToolMetadata interface with riskLevel and requiresConfirmation
  • Default risk levels assigned to all builtin tools
  • MCP tools default to requiresConfirmation: true
  • Agentic loop pauses before executing tools that require confirmation
  • Denied tools send "denied by user" message back to LLM
  • Confirmation callback is optional — if not provided, all tools auto-approve (backward compatible)
  • LLM receives denied message and can adjust its approach

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions