all: remove multiplechoice tool

It's rarely used; doesn't pull its weight.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s11d827ec20c6ddb8k
diff --git a/cmd/go2ts/go2ts.go b/cmd/go2ts/go2ts.go
index 6025026..a4015e0 100644
--- a/cmd/go2ts/go2ts.go
+++ b/cmd/go2ts/go2ts.go
@@ -66,8 +66,6 @@
 		server.GitPushInfoResponse{},
 		server.GitPushRequest{},
 		server.GitPushResponse{},
-		loop.MultipleChoiceOption{},
-		loop.MultipleChoiceParams{},
 		git_tools.DiffFile{},
 		git_tools.GitLogEntry{},
 	)
diff --git a/loop/agent.go b/loop/agent.go
index 40bbb20..c98e7f7 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -1377,12 +1377,6 @@
 		claudetool.Think, claudetool.TodoRead, claudetool.TodoWrite, a.commitMessageStyleTool(), makeDoneTool(a.codereview),
 		a.codereview.Tool(), claudetool.AboutSketch,
 	}
-
-	// One-shot mode is non-interactive, multiple choice requires human response
-	if !a.config.OneShot {
-		convo.Tools = append(convo.Tools, multipleChoiceTool)
-	}
-
 	convo.Tools = append(convo.Tools, browserTools...)
 
 	// Add MCP tools if configured
@@ -1434,59 +1428,6 @@
 	return convo
 }
 
-var multipleChoiceTool = &llm.Tool{
-	Name:        "multiplechoice",
-	Description: "Present the user with an quick way to answer to your question using one of a short list of possible answers you would expect from the user.",
-	EndsTurn:    true,
-	InputSchema: json.RawMessage(`{
-  "type": "object",
-  "description": "The question and a list of answers you would expect the user to choose from.",
-  "properties": {
-    "question": {
-      "type": "string",
-      "description": "The text of the multiple-choice question you would like the user, e.g. 'What kinds of test cases would you like me to add?'"
-    },
-    "responseOptions": {
-      "type": "array",
-      "description": "The set of possible answers to let the user quickly choose from, e.g. ['Basic unit test coverage', 'Error return values', 'Malformed input'].",
-      "items": {
-        "type": "object",
-        "properties": {
-          "caption": {
-            "type": "string",
-            "description": "The caption, e.g. 'Basic coverage', 'Error return values', or 'Malformed input' for the response button. Do NOT include options for responses that would end the conversation like 'Ok', 'No thank you', 'This looks good'"
-          },
-          "responseText": {
-            "type": "string",
-            "description": "The full text of the response, e.g. 'Add unit tests for basic test coverage', 'Add unit tests for error return values', or 'Add unit tests for malformed input'"
-          }
-        },
-        "required": ["caption", "responseText"]
-      }
-    }
-  },
-  "required": ["question", "responseOptions"]
-}`),
-	Run: func(ctx context.Context, input json.RawMessage) llm.ToolOut {
-		// The Run logic for "multiplechoice" tool is a no-op on the server.
-		// The UI will present a list of options for the user to select from,
-		// and that's it as far as "executing" the tool_use goes.
-		// When the user *does* select one of the presented options, that
-		// responseText gets sent as a chat message on behalf of the user.
-		return llm.ToolOut{LLMContent: llm.TextContent("end your turn and wait for the user to respond")}
-	},
-}
-
-type MultipleChoiceOption struct {
-	Caption      string `json:"caption"`
-	ResponseText string `json:"responseText"`
-}
-
-type MultipleChoiceParams struct {
-	Question        string                 `json:"question"`
-	ResponseOptions []MultipleChoiceOption `json:"responseOptions"`
-}
-
 // branchExists reports whether branchName exists, either locally or in well-known remotes.
 func branchExists(dir, branchName string) bool {
 	refs := []string{
diff --git a/loop/agent_system_prompt.txt b/loop/agent_system_prompt.txt
index 2d60f72..0faf441 100644
--- a/loop/agent_system_prompt.txt
+++ b/loop/agent_system_prompt.txt
@@ -63,19 +63,6 @@
 Before modifying any file, you MUST proactively read and follow all guidance files in its directory and all parent directories.
 When guidance files conflict, more-deeply-nested files take precedence.
 Direct user instructions from the current conversation always take highest precedence.
-
-IMPORTANT: When the user provides feedback about how they want Sketch to behave, use the multiplechoice tool to ask whether to record this in a dear_llm.md file.
-If you think "I should remember this" - stop - and use multiplechoice instead.
-
-Always present all three of these options:
-
-+ 1. "Yes, for all future work" - Record in root dear_llm.md
-+ 2. "Yes, but only for directory X" - Record in X/dear_llm.md
-+ 3. "No" - Don't record this feedback
-
-When presenting this choice, the question must include a preview of exactly what would be written to the dear_llm.md file.
-For example: "Should I remember: 'Prefer table-driven tests over multiple separate test functions.'?"
-Changes to dear_llm.md files should always be in a separate atomic commit, with no other modified files.
 </customization>
 
 <guidance>
diff --git a/loop/testdata/agent_loop.httprr b/loop/testdata/agent_loop.httprr
index b2ac507..ee2cfa3 100644
--- a/loop/testdata/agent_loop.httprr
+++ b/loop/testdata/agent_loop.httprr
@@ -1,9 +1,9 @@
 httprr trace v1
-20094 2538
+18529 2497
 POST https://api.anthropic.com/v1/messages HTTP/1.1

 Host: api.anthropic.com

 User-Agent: Go-http-client/1.1

-Content-Length: 19896

+Content-Length: 18331

 Anthropic-Version: 2023-06-01

 Content-Type: application/json

 

@@ -291,45 +291,6 @@
    }
   },
   {
-   "name": "multiplechoice",
-   "description": "Present the user with an quick way to answer to your question using one of a short list of possible answers you would expect from the user.",
-   "input_schema": {
-    "type": "object",
-    "description": "The question and a list of answers you would expect the user to choose from.",
-    "properties": {
-     "question": {
-      "type": "string",
-      "description": "The text of the multiple-choice question you would like the user, e.g. 'What kinds of test cases would you like me to add?'"
-     },
-     "responseOptions": {
-      "type": "array",
-      "description": "The set of possible answers to let the user quickly choose from, e.g. ['Basic unit test coverage', 'Error return values', 'Malformed input'].",
-      "items": {
-       "type": "object",
-       "properties": {
-        "caption": {
-         "type": "string",
-         "description": "The caption, e.g. 'Basic coverage', 'Error return values', or 'Malformed input' for the response button. Do NOT include options for responses that would end the conversation like 'Ok', 'No thank you', 'This looks good'"
-        },
-        "responseText": {
-         "type": "string",
-         "description": "The full text of the response, e.g. 'Add unit tests for basic test coverage', 'Add unit tests for error return values', or 'Add unit tests for malformed input'"
-        }
-       },
-       "required": [
-        "caption",
-        "responseText"
-       ]
-      }
-     }
-    },
-    "required": [
-     "question",
-     "responseOptions"
-    ]
-   }
-  },
-  {
    "name": "browser_navigate",
    "description": "Navigate the browser to a specific URL and wait for page to load",
    "input_schema": {
@@ -587,24 +548,24 @@
 Anthropic-Organization-Id: 3c473a21-7208-450a-a9f8-80aebda45c1b

 Anthropic-Ratelimit-Input-Tokens-Limit: 2000000

 Anthropic-Ratelimit-Input-Tokens-Remaining: 2000000

-Anthropic-Ratelimit-Input-Tokens-Reset: 2025-07-23T00:51:23Z

+Anthropic-Ratelimit-Input-Tokens-Reset: 2025-07-23T18:04:13Z

 Anthropic-Ratelimit-Output-Tokens-Limit: 400000

 Anthropic-Ratelimit-Output-Tokens-Remaining: 400000

-Anthropic-Ratelimit-Output-Tokens-Reset: 2025-07-23T00:51:27Z

+Anthropic-Ratelimit-Output-Tokens-Reset: 2025-07-23T18:04:18Z

 Anthropic-Ratelimit-Requests-Limit: 4000

 Anthropic-Ratelimit-Requests-Remaining: 3999

-Anthropic-Ratelimit-Requests-Reset: 2025-07-23T00:51:20Z

+Anthropic-Ratelimit-Requests-Reset: 2025-07-23T18:04:12Z

 Anthropic-Ratelimit-Tokens-Limit: 2400000

 Anthropic-Ratelimit-Tokens-Remaining: 2400000

-Anthropic-Ratelimit-Tokens-Reset: 2025-07-23T00:51:23Z

+Anthropic-Ratelimit-Tokens-Reset: 2025-07-23T18:04:13Z

 Cf-Cache-Status: DYNAMIC

-Cf-Ray: 963730571c2eeb29-SJC

+Cf-Ray: 963d1951fa4567e9-SJC

 Content-Type: application/json

-Date: Wed, 23 Jul 2025 00:51:27 GMT

-Request-Id: req_011CRP2vuuf7xj5V5QqTaEuS

+Date: Wed, 23 Jul 2025 18:04:18 GMT

+Request-Id: req_011CRQPh7JZsCN9bRzBcZiu6

 Server: cloudflare

 Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

 Via: 1.1 google

 X-Robots-Tag: none

 

-{"id":"msg_01MsAHgr98YWT6BpHDitnPPM","type":"message","role":"assistant","model":"claude-sonnet-4-20250514","content":[{"type":"text","text":"Here are the tools available to me:\n\n**File & Code Operations:**\n- `bash` - Execute shell commands\n- `patch` - Edit files with precise text modifications\n- `keyword_search` - Search codebase by keywords and concepts\n\n**Project Management:**\n- `todo_read` / `todo_write` - Manage task lists\n- `think` - Record thoughts and planning\n- `done` - Complete work with verification checklist\n\n**Git & Code Quality:**\n- `commit-message-style` - Get git commit message guidance\n- `codereview` - Run automated code review\n\n**Browser Automation:**\n- `browser_navigate` - Navigate to URLs\n- `browser_click` - Click elements\n- `browser_type` - Type into inputs\n- `browser_wait_for` - Wait for elements\n- `browser_get_text` - Read page text\n- `browser_eval` - Execute JavaScript\n- `browser_scroll_into_view` - Scroll to elements\n- `browser_resize` - Resize browser window\n- `browser_recent_console_logs` - Get console logs\n- `browser_clear_console_logs` - Clear console logs\n- `browser_take_screenshot` - Take screenshots\n\n**Utilities:**\n- `read_image` - Read and encode image files\n- `multiplechoice` - Present multiple choice questions\n- `about_sketch` - Get help with Sketch functionality"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":4606,"cache_read_input_tokens":0,"output_tokens":323,"service_tier":"standard"}}
\ No newline at end of file
+{"id":"msg_01EGxSVYkNrBjKc5foxF4frd","type":"message","role":"assistant","model":"claude-sonnet-4-20250514","content":[{"type":"text","text":"Here are the tools available to me:\n\n**File & Code Management:**\n- `bash` - Execute shell commands\n- `patch` - Modify files with precise text edits\n- `keyword_search` - Search codebase by keywords\n\n**Task Management:**\n- `todo_read` - Read current todo list\n- `todo_write` - Create/manage task list\n- `think` - Take notes and form plans\n\n**Git & Code Quality:**\n- `commit-message-style` - Get git commit message guidance\n- `codereview` - Run automated code review\n- `done` - Mark completion with checklist verification\n\n**Browser Automation:**\n- `browser_navigate` - Navigate to URLs\n- `browser_click` - Click elements\n- `browser_type` - Type into inputs\n- `browser_wait_for` - Wait for elements\n- `browser_get_text` - Read element text\n- `browser_eval` - Execute JavaScript\n- `browser_scroll_into_view` - Scroll to elements\n- `browser_resize` - Resize browser window\n- `browser_take_screenshot` - Capture screenshots\n- `browser_recent_console_logs` - Get console logs\n- `browser_clear_console_logs` - Clear console logs\n\n**Utilities:**\n- `read_image` - Read and encode image files\n- `about_sketch` - Get help with Sketch functionality"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":4261,"cache_read_input_tokens":0,"output_tokens":319,"service_tier":"standard"}}
\ No newline at end of file
diff --git a/termui/termui.go b/termui/termui.go
index 1ed7496..bc8a610 100644
--- a/termui/termui.go
+++ b/termui/termui.go
@@ -51,11 +51,6 @@
 📚 About Sketch
 {{else if eq .msg.ToolName "codereview" -}}
  🐛  Running automated code review, may be slow
-{{else if eq .msg.ToolName "multiplechoice" -}}
- 📝 {{.input.question}}
-{{ range .input.responseOptions -}}
-  - {{ .caption}}: {{.responseText}}
-{{end -}}
 {{else if eq .msg.ToolName "browser_navigate" -}}
  🌐 {{.input.url -}}
 {{else if eq .msg.ToolName "browser_click" -}}
diff --git a/webui/src/types.ts b/webui/src/types.ts
index b333657..a4f2154 100644
--- a/webui/src/types.ts
+++ b/webui/src/types.ts
@@ -146,16 +146,6 @@
 	error?: string;
 }
 
-export interface MultipleChoiceOption {
-	caption: string;
-	responseText: string;
-}
-
-export interface MultipleChoiceParams {
-	question: string;
-	responseOptions: MultipleChoiceOption[] | null;
-}
-
 export interface DiffFile {
 	path: string;
 	old_path: string;
diff --git a/webui/src/web-components/mobile-chat.ts b/webui/src/web-components/mobile-chat.ts
index 0c3bc48..b8c0ec2 100644
--- a/webui/src/web-components/mobile-chat.ts
+++ b/webui/src/web-components/mobile-chat.ts
@@ -272,15 +272,6 @@
         case "todo_read":
           return "Read todo list";
 
-        case "multiplechoice":
-          const question = input.question || "Multiple choice question";
-          const options = input.responseOptions || [];
-          if (options.length > 0) {
-            const optionsList = options.map((opt) => opt.caption).join(", ");
-            return `${question} [${optionsList}]`;
-          }
-          return question;
-
         case "done":
           return "Task completion checklist";
 
diff --git a/webui/src/web-components/sketch-app-shell-base.ts b/webui/src/web-components/sketch-app-shell-base.ts
index 0b5e043..e0fe471 100644
--- a/webui/src/web-components/sketch-app-shell-base.ts
+++ b/webui/src/web-components/sketch-app-shell-base.ts
@@ -155,8 +155,6 @@
     this._handleViewModeSelect = this._handleViewModeSelect.bind(this);
     this._handlePopState = this._handlePopState.bind(this);
     this._handleShowCommitDiff = this._handleShowCommitDiff.bind(this);
-    this._handleMutlipleChoiceSelected =
-      this._handleMutlipleChoiceSelected.bind(this);
     this._handlePushRebaseRequest = this._handlePushRebaseRequest.bind(this);
     this._handleStopClick = this._handleStopClick.bind(this);
     this._handleEndClick = this._handleEndClick.bind(this);
@@ -205,10 +203,6 @@
     window.addEventListener("focus", this._handleWindowFocus);
     window.addEventListener("blur", this._handleWindowBlur);
     window.addEventListener(
-      "multiple-choice-selected",
-      this._handleMutlipleChoiceSelected,
-    );
-    window.addEventListener(
       "push-rebase-request",
       this._handlePushRebaseRequest,
     );
@@ -257,10 +251,6 @@
     window.removeEventListener("focus", this._handleWindowFocus);
     window.removeEventListener("blur", this._handleWindowBlur);
     window.removeEventListener(
-      "multiple-choice-selected",
-      this._handleMutlipleChoiceSelected,
-    );
-    window.removeEventListener(
       "push-rebase-request",
       this._handlePushRebaseRequest,
     );
@@ -764,24 +754,6 @@
     }
   }
 
-  async _handleMutlipleChoiceSelected(e: CustomEvent) {
-    const chatInput = this.querySelector(
-      "sketch-chat-input",
-    ) as SketchChatInput;
-    if (chatInput) {
-      if (chatInput.content && chatInput.content.trim() !== "") {
-        chatInput.content += "\n\n";
-      }
-      chatInput.content += e.detail.responseText;
-      chatInput.focus();
-      // Adjust textarea height to accommodate new content
-      requestAnimationFrame(() => {
-        if (chatInput.adjustChatSpacing) {
-          chatInput.adjustChatSpacing();
-        }
-      });
-    }
-  }
 
   async _handlePushRebaseRequest(e: CustomEvent) {
     const chatInput = this.querySelector(
diff --git a/webui/src/web-components/sketch-tool-calls.ts b/webui/src/web-components/sketch-tool-calls.ts
index 826052d..c255ef7 100644
--- a/webui/src/web-components/sketch-tool-calls.ts
+++ b/webui/src/web-components/sketch-tool-calls.ts
@@ -53,11 +53,6 @@
           .open=${open}
           .toolCall=${toolCall}
         ></sketch-tool-card-done>`;
-      case "multiplechoice":
-        return html`<sketch-tool-card-multiple-choice
-          .open=${open}
-          .toolCall=${toolCall}
-        ></sketch-tool-card-multiple-choice>`;
       case "patch":
         return html`<sketch-tool-card-patch
           .open=${open}
diff --git a/webui/src/web-components/sketch-tool-card.ts b/webui/src/web-components/sketch-tool-card.ts
index 5c5e4c2..0c6bb1e 100644
--- a/webui/src/web-components/sketch-tool-card.ts
+++ b/webui/src/web-components/sketch-tool-card.ts
@@ -3,8 +3,6 @@
 import { customElement, property } from "lit/decorators.js";
 import {
   ToolCall,
-  MultipleChoiceOption,
-  MultipleChoiceParams,
   State,
 } from "../types";
 import { marked } from "marked";
@@ -299,100 +297,6 @@
   }
 }
 
-@customElement("sketch-tool-card-multiple-choice")
-export class SketchToolCardMultipleChoice extends SketchTailwindElement {
-  @property() toolCall: ToolCall;
-  @property() open: boolean;
-  @property() selectedOption: MultipleChoiceOption = null;
-
-  connectedCallback() {
-    super.connectedCallback();
-    this.updateSelectedOption();
-  }
-
-  updated(changedProps) {
-    if (changedProps.has("toolCall")) {
-      this.updateSelectedOption();
-    }
-  }
-
-  updateSelectedOption() {
-    if (this.toolCall?.result_message?.tool_result) {
-      try {
-        this.selectedOption = JSON.parse(
-          this.toolCall.result_message.tool_result,
-        ).selected;
-      } catch (e) {
-        console.error("Error parsing result:", e);
-      }
-    } else {
-      this.selectedOption = null;
-    }
-  }
-
-  async handleOptionClick(choice) {
-    this.selectedOption = this.selectedOption === choice ? null : choice;
-
-    const event = new CustomEvent("multiple-choice-selected", {
-      detail: {
-        responseText: this.selectedOption.responseText,
-        toolCall: this.toolCall,
-      },
-      bubbles: true,
-      composed: true,
-    });
-    this.dispatchEvent(event);
-  }
-
-  render() {
-    let choices = [];
-    let question = "";
-    try {
-      const inputData = JSON.parse(
-        this.toolCall?.input || "{}",
-      ) as MultipleChoiceParams;
-      choices = inputData.responseOptions || [];
-      question = inputData.question || "Please select an option:";
-    } catch (e) {
-      console.error("Error parsing multiple-choice input:", e);
-    }
-
-    const summaryContent =
-      this.selectedOption !== null
-        ? html`<span class="italic p-2">
-            ${question}:
-            <strong class="not-italic text-blue-600 font-semibold"
-              >${this.selectedOption.caption}</strong
-            >
-          </span>`
-        : html`<span class="italic p-2">${question}</span>`;
-
-    const inputContent = html`<div class="flex flex-row flex-wrap gap-2 my-2">
-      ${choices.map((choice) => {
-        const isSelected =
-          this.selectedOption !== null && this.selectedOption === choice;
-        return html`
-          <div
-            class="inline-flex items-center px-3 py-2 rounded cursor-pointer transition-all duration-200 border select-none ${isSelected
-              ? "bg-blue-50 border-blue-500"
-              : "bg-gray-100 border-transparent hover:bg-gray-200 hover:border-gray-400 hover:-translate-y-px hover:shadow-md active:translate-y-0 active:shadow-sm active:bg-gray-300"}"
-            @click=${() => this.handleOptionClick(choice)}
-            title="${choice.responseText}"
-          >
-            <span class="option-label">${choice.caption}</span>
-            ${isSelected
-              ? html`<span class="ml-1.5 text-blue-600">✓</span>`
-              : ""}
-          </div>
-        `;
-      })}
-    </div>`;
-
-    return html`<div class="multiple-choice-card">
-      ${summaryContent} ${inputContent}
-    </div>`;
-  }
-}
 
 @customElement("sketch-tool-card-todo-write")
 export class SketchToolCardTodoWrite extends SketchTailwindElement {
@@ -545,7 +449,6 @@
     "sketch-tool-card-patch": SketchToolCardPatch;
     "sketch-tool-card-think": SketchToolCardThink;
     "sketch-tool-card-commit-message-style": SketchToolCardCommitMessageStyle;
-    "sketch-tool-card-multiple-choice": SketchToolCardMultipleChoice;
     "sketch-tool-card-todo-write": SketchToolCardTodoWrite;
     "sketch-tool-card-todo-read": SketchToolCardTodoRead;
     "sketch-tool-card-keyword-search": SketchToolCardKeywordSearch;