refactor: remove todo tool (#35989)

This commit is contained in:
Aiden Cline 2026-07-09 00:13:48 -05:00 committed by GitHub
commit 7feefb697f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
250 changed files with 237 additions and 4755 deletions

View file

@ -590,27 +590,6 @@
}
}
[data-component="todos"] {
padding: 10px 0 24px 0;
display: flex;
flex-direction: column;
gap: 8px;
[data-component="checkbox"] {
--checkbox-align: flex-start;
--checkbox-offset: 0.5px;
}
[data-slot="message-part-todo-content"] {
line-height: var(--line-height-normal);
&[data-completed="completed"] {
text-decoration: line-through;
color: var(--v2-text-text-faint);
}
}
}
[data-component="context-tool-group-trigger"] {
width: 100%;
min-height: 24px;
@ -694,7 +673,6 @@
[data-component="bash-output"],
[data-component="edit-content"],
[data-component="write-content"],
[data-component="todos"],
[data-component="diagnostics"],
.error-card {
-webkit-user-select: text;
@ -1389,10 +1367,6 @@ body:not([data-new-layout]) {
color: var(--text-interactive-base);
}
[data-slot="message-part-todo-content"][data-completed="completed"] {
color: var(--text-weaker);
}
[data-component="diagnostics"] {
background-color: var(--surface-critical-weak);
border-top: 1px solid var(--border-critical-base);

View file

@ -27,7 +27,6 @@ import {
TextPart,
ToolPart,
UserMessage,
Todo,
QuestionAnswer,
QuestionInfo,
} from "@opencode-ai/sdk/v2"
@ -42,7 +41,6 @@ import { Collapsible } from "@opencode-ai/ui/collapsible"
import { FileIcon } from "@opencode-ai/ui/file-icon"
import { Icon } from "@opencode-ai/ui/icon"
import { ToolErrorCard } from "./tool-error-card"
import { Checkbox } from "@opencode-ai/ui/checkbox"
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
import { Markdown } from "./markdown"
import { ImagePreview } from "@opencode-ai/ui/image-preview"
@ -545,11 +543,6 @@ export function getToolInfo(
? `${input.files.length} ${i18n.t(input.files.length > 1 ? "ui.common.file.other" : "ui.common.file.one")}`
: undefined,
}
case "todowrite":
return {
icon: "checklist",
title: i18n.t("ui.tool.todos"),
}
case "question":
return {
icon: "bubble-5",
@ -613,8 +606,6 @@ function taskSession(
}
const CONTEXT_GROUP_TOOLS = new Set(["read", "glob", "grep", "list"])
const HIDDEN_TOOLS = new Set(["todowrite"])
function list<T>(value: T[] | undefined | null, fallback: T[]) {
if (Array.isArray(value)) return value
return fallback
@ -718,7 +709,6 @@ function index<T extends { id: string }>(items: readonly T[]) {
export function renderable(part: PartType, showReasoningSummaries = true) {
if (part.type === "tool") {
if (HIDDEN_TOOLS.has(part.tool)) return false
if (part.tool === "question") return part.state.status !== "pending" && part.state.status !== "running"
return true
}
@ -1498,8 +1488,6 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
const data = useData()
const i18n = useI18n()
const part = () => props.part as ToolPart
if (part().tool === "todowrite") return null
const hideQuestion = createMemo(
() => part().tool === "question" && (part().state.status === "pending" || part().state.status === "running"),
)
@ -2476,57 +2464,6 @@ ToolRegistry.register({
},
})
ToolRegistry.register({
name: "todowrite",
render(props) {
const i18n = useI18n()
const todos = createMemo(() => {
const meta = props.metadata?.todos
if (Array.isArray(meta)) return meta
const input = props.input.todos
if (Array.isArray(input)) return input
return []
})
const subtitle = createMemo(() => {
const list = todos()
if (list.length === 0) return ""
return `${list.filter((t: Todo) => t.status === "completed").length}/${list.length}`
})
return (
<BasicTool
{...props}
defaultOpen
icon="checklist"
trigger={{
title: i18n.t("ui.tool.todos"),
subtitle: subtitle(),
}}
>
<Show when={todos().length}>
<div data-component="todos">
<For each={todos()}>
{(todo: Todo) => (
<Checkbox readOnly checked={todo.status === "completed"}>
<span
data-slot="message-part-todo-content"
data-completed={todo.status === "completed" ? "completed" : undefined}
>
{todo.content}
</span>
</Checkbox>
)}
</For>
</div>
</Show>
</BasicTool>
)
},
})
ToolRegistry.register({
name: "question",
render(props) {

View file

@ -104,11 +104,8 @@ function summaryDiff(value: SummaryDiffInput): value is SummaryDiff {
)
}
const hidden = new Set(["todowrite"])
function partState(part: PartType, showReasoningSummaries: boolean) {
if (part.type === "tool") {
if (hidden.has(part.tool)) return
if (part.tool === "question" && (part.state.status === "pending" || part.state.status === "running")) return
return "visible" as const
}

View file

@ -399,25 +399,6 @@ const TOOL_SAMPLES = {
title: "playwriter",
metadata: {},
},
todowrite: {
tool: "todowrite",
input: {
todos: [
{ content: "Create data generators", status: "completed", priority: "high" },
{ content: "Build UI controls", status: "in_progress", priority: "high" },
{ content: "Add CSS export", status: "pending", priority: "medium" },
],
},
output: "",
title: "Todos",
metadata: {
todos: [
{ content: "Create data generators", status: "completed", priority: "high" },
{ content: "Build UI controls", status: "in_progress", priority: "high" },
{ content: "Add CSS export", status: "pending", priority: "medium" },
],
},
},
}
// ---------------------------------------------------------------------------