feat: apply_patch tool for openai models (#9127)

This commit is contained in:
Aiden Cline
2026-01-17 22:35:09 -08:00
committed by GitHub
parent 10433cb45b
commit b7ad6bd839
16 changed files with 1122 additions and 496 deletions

View File

@@ -689,3 +689,75 @@
}
}
}
[data-component="apply-patch-files"] {
display: flex;
flex-direction: column;
}
[data-component="apply-patch-file"] {
display: flex;
flex-direction: column;
border-top: 1px solid var(--border-weaker-base);
&:first-child {
border-top: 1px solid var(--border-weaker-base);
}
[data-slot="apply-patch-file-header"] {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background-color: var(--surface-inset-base);
}
[data-slot="apply-patch-file-action"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
color: var(--text-base);
flex-shrink: 0;
&[data-type="delete"] {
color: var(--text-critical-base);
}
&[data-type="add"] {
color: var(--text-success-base);
}
&[data-type="move"] {
color: var(--text-warning-base);
}
}
[data-slot="apply-patch-file-path"] {
font-family: var(--font-family-mono);
font-size: var(--font-size-small);
color: var(--text-weak);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-grow: 1;
}
[data-slot="apply-patch-deletion-count"] {
font-family: var(--font-family-mono);
font-size: var(--font-size-small);
color: var(--text-critical-base);
flex-shrink: 0;
}
}
[data-component="apply-patch-file-diff"] {
max-height: 420px;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}

View File

@@ -233,6 +233,12 @@ export function getToolInfo(tool: string, input: any = {}): ToolInfo {
title: "Write",
subtitle: input.filePath ? getFilename(input.filePath) : undefined,
}
case "apply_patch":
return {
icon: "code-lines",
title: "Patch",
subtitle: input.files?.length ? `${input.files.length} file${input.files.length > 1 ? "s" : ""}` : undefined,
}
case "todowrite":
return {
icon: "checklist",
@@ -1027,6 +1033,94 @@ ToolRegistry.register({
},
})
interface ApplyPatchFile {
filePath: string
relativePath: string
type: "add" | "update" | "delete" | "move"
diff: string
before: string
after: string
additions: number
deletions: number
movePath?: string
}
ToolRegistry.register({
name: "apply_patch",
render(props) {
const diffComponent = useDiffComponent()
const files = createMemo(() => (props.metadata.files ?? []) as ApplyPatchFile[])
const subtitle = createMemo(() => {
const count = files().length
if (count === 0) return ""
return `${count} file${count > 1 ? "s" : ""}`
})
return (
<BasicTool
{...props}
icon="code-lines"
trigger={{
title: "Patch",
subtitle: subtitle(),
}}
>
<Show when={files().length > 0}>
<div data-component="apply-patch-files">
<For each={files()}>
{(file) => (
<div data-component="apply-patch-file">
<div data-slot="apply-patch-file-header">
<Switch>
<Match when={file.type === "delete"}>
<span data-slot="apply-patch-file-action" data-type="delete">
Deleted
</span>
</Match>
<Match when={file.type === "add"}>
<span data-slot="apply-patch-file-action" data-type="add">
Created
</span>
</Match>
<Match when={file.type === "move"}>
<span data-slot="apply-patch-file-action" data-type="move">
Moved
</span>
</Match>
<Match when={file.type === "update"}>
<span data-slot="apply-patch-file-action" data-type="update">
Patched
</span>
</Match>
</Switch>
<span data-slot="apply-patch-file-path">{file.relativePath}</span>
<Show when={file.type !== "delete"}>
<DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} />
</Show>
<Show when={file.type === "delete"}>
<span data-slot="apply-patch-deletion-count">-{file.deletions}</span>
</Show>
</div>
<Show when={file.type !== "delete"}>
<div data-component="apply-patch-file-diff">
<Dynamic
component={diffComponent}
before={{ name: file.filePath, contents: file.before }}
after={{ name: file.filePath, contents: file.after }}
/>
</div>
</Show>
</div>
)}
</For>
</div>
</Show>
</BasicTool>
)
},
})
ToolRegistry.register({
name: "todowrite",
render(props) {