microsoft / microsoft/TypeAgent

Reasoning Action needs user confirmation for tool calls like CoPilot/Claude

Open
#2,627 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

dispatcher enhancement reasoning security
Dominant language
TypeScript
Stars
740
Forks
106
Avg merge
1d 6h
Merged PRs (30d)
84

Description

Problem

The dispatcher's Reasoning Action (the ReasoningAction fallback that routes complex requests into an LLM reasoning loop) executes tool calls without asking the user for confirmation. Both reasoning adapters auto-approve every tool call:

  • Claude: canUseTool: async () => ({ behavior: "allow" }) + permissionMode: "acceptEdits"packages/dispatcher/dispatcher/src/reasoning/claude.ts (~L584-586)
  • Copilot: onPermissionRequest: approveAllpackages/dispatcher/dispatcher/src/reasoning/copilot.ts (L15 import, L647)
  • Shared adapter: canUseTool: async () => ({ behavior: "allow" })packages/dispatcher/dispatcher/src/reasoning/claudeSDKAdapter.ts (~L155)

The reasoning loop exposes tools including execute_action (runs real, side-effecting dispatcher actions), discover_actions, search_memory, and remember. Because approval is hard-wired to allow-all, the loop can perform side-effecting actions (send email, modify lists, browser automation, etc.) with no human in the loop.

Desired behavior

Before executing a side-effecting reasoning tool call, prompt the user to confirm — the same UX GitHub Copilot and Claude use ("Allow / Deny", ideally with "Allow always for this tool/session"):

  • Show the tool name and a human-readable summary of the arguments (e.g., which action + parameters execute_action is about to run).
  • Offer Allow once / Deny / Allow for session.
  • Deny aborts that tool call and feeds the denial back into the loop so the model can adapt.
  • Read-only tools (discover_actions, search_memory) may run without a prompt; side-effecting tools (execute_action, remember, browser actions) prompt by default.

Suggested approach (implementation notes)

  • Reuse SessionContext.popupQuestion(message, choices, defaultId) (packages/dispatcher/dispatcher/src/execute/sessionContext.ts ~L222) — it already round-trips to the Shell/CLI/RPC clientIO.
  • Add an SDK-agnostic gating hook to ReasoningLoopConfig (packages/dispatcher/dispatcher/src/reasoning/reasoningLoopBase.ts), e.g. onToolApproval?(tool, args): Promise<"allow" | "deny" | "allow_always">. The base already has informational onToolCall/onToolResult callbacks (L31-32); this adds a gating counterpart.
  • Wire real permission callbacks in both adapters instead of allow-all:
    • Copilot: replace onPermissionRequest: approveAllcopilot.ts L647.
    • Claude: replace the canUseTool allow-all — claude.ts ~L586 and claudeSDKAdapter.ts ~L155.
  • Follow the workflow engine's secure-by-default ApprovalFn precedent (examples/workflow/model/src/taskDefinition.ts ~L175, examples/workflow/engine/src/runner.ts; design doc docs/architecture/workflows/engineering/task-policy-temp.md).
  • Add a policy/toggle under the existing reasoning config (config.defaults.yaml ~L14): prompt (default) / allow / per-tool, plus an "allow all" escape hatch for headless runs (mirrors the workflow CLI --allow-all / --dry-run).

The auto-approve posture is already documented as deliberately temporary in docs/architecture/workflows/ir/decisions/0010-copilot-task-family.md §7, which points toward a capability-based permission model.

Acceptance criteria

  • Side-effecting reasoning tool calls prompt for confirmation before executing (Copilot + Claude adapters).
  • The prompt shows the tool name + summarized args.
  • Allow / Deny / Allow-for-session work; Deny aborts the call and the loop continues gracefully.
  • Read-only tools do not prompt (configurable).
  • A config/flag can auto-approve all for headless/automated scenarios, off by default.
  • Works across Shell, CLI, and RPC clients via popupQuestion / clientIO.

Out of scope

  • Full capability-based security model (tracked separately per decision 0010 §7).
  • Per-agent permission policies beyond the reasoning loop.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ReasoningLoopConfig in packages/dispatcher/dispatcher/src/reasoning/reasoningLoopBase.ts and SessionContext.popupQuestion in packages/dispatcher/dispatcher/src/execute/sessionContext.ts, then trace the permission callbacks in reasoning/copilot.ts, reasoning/claude.ts, and reasoning/claudeSDKAdapter.ts. Compare the workflow engine's ApprovalFn precedent and existing reasoning configuration before making the change. Done means side-effecting tools prompt through Shell, CLI, and RPC clients, read-only tools remain unprompted, denial continues the loop, and headless auto-approval is opt-in.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authorization, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.