Skip to content

Commit e02741c

Browse files
committed
edit tool first take
1 parent ed03f5a commit e02741c

File tree

8 files changed

+97
-18
lines changed

8 files changed

+97
-18
lines changed

core/tools/builtIn.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export enum BuiltInToolNames {
22
ReadFile = "builtin_read_file",
3+
EditExistingFile = "builtin_edit_existing_file",
34
ReadCurrentlyOpenFile = "builtin_read_currently_open_file",
45
CreateNewFile = "builtin_create_new_file",
56
RunTerminalCommand = "builtin_run_terminal_command",

core/tools/callTool.ts

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { canParseUrl } from "../util/url";
44
import { BuiltInToolNames } from "./builtIn";
55

66
import { createNewFileImpl } from "./implementations/createNewFile";
7+
import { editFileImpl } from "./implementations/editFile";
78
import { exactSearchImpl } from "./implementations/exactSearch";
89
import { lsToolImpl } from "./implementations/lsTool";
910
import { readCurrentlyOpenFileImpl } from "./implementations/readCurrentlyOpenFile";
@@ -138,6 +139,8 @@ export async function callTool(
138139
switch (uri) {
139140
case BuiltInToolNames.ReadFile:
140141
return await readFileImpl(args, extras);
142+
case BuiltInToolNames.EditExistingFile:
143+
return await editFileImpl(args, extras);
141144
case BuiltInToolNames.CreateNewFile:
142145
return await createNewFileImpl(args, extras);
143146
case BuiltInToolNames.ExactSearch:

core/tools/definitions/editFile.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Tool } from "../..";
2+
import { BUILT_IN_GROUP_NAME, BuiltInToolNames } from "../builtIn";
3+
4+
export const editFileTool: Tool = {
5+
type: "function",
6+
displayTitle: "Edit File",
7+
wouldLikeTo: "edit {{{ filepath }}}",
8+
isCurrently: "editing {{{ filepath }}}",
9+
hasAlready: "edited {{{ filepath }}}",
10+
group: BUILT_IN_GROUP_NAME,
11+
readonly: false,
12+
function: {
13+
name: BuiltInToolNames.EditExistingFile,
14+
description:
15+
"To edit an existing file, call this tool and follow the returned instructions. If you don't have the contents of the file, read it first.",
16+
parameters: {
17+
type: "object",
18+
required: ["filepath"],
19+
properties: {
20+
filepath: {
21+
type: "string",
22+
description:
23+
"The path of the file to edit, relative to the root of the workspace.",
24+
},
25+
},
26+
},
27+
},
28+
};
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ToolImpl } from ".";
2+
import { resolveRelativePathInDir } from "../../util/ideUtils";
3+
4+
export const EDIT_TOOL_CONTEXT_ITEM_NAME = "Edit Tool Instructions";
5+
6+
export const editFileImpl: ToolImpl = async (args, extras) => {
7+
const firstUriMatch = await resolveRelativePathInDir(
8+
args.filepath,
9+
extras.ide,
10+
);
11+
if (!firstUriMatch) {
12+
throw new Error(`File ${args.filepath} does not exist.`);
13+
}
14+
return [
15+
{
16+
name: EDIT_TOOL_CONTEXT_ITEM_NAME,
17+
description: "Instructions for editing the file",
18+
content:
19+
"Edit Instructions: return the full new file contents in a codeblock. The codeblock header should be of the format '```language filepath'",
20+
},
21+
];
22+
};

core/tools/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createNewFileTool } from "./definitions/createNewFile";
2+
import { editFileTool } from "./definitions/editFile";
23
import { exactSearchTool } from "./definitions/exactSearch";
34
import { lsTool } from "./definitions/lsTool";
45
import { readCurrentlyOpenFileTool } from "./definitions/readCurrentlyOpenFile";
@@ -9,6 +10,7 @@ import { viewDiffTool } from "./definitions/viewDiff";
910

1011
export const allTools = [
1112
readFileTool,
13+
editFileTool,
1214
createNewFileTool,
1315
runTerminalCommandTool,
1416

gui/src/components/markdown/StepContainerPreToolbar/StepContainerPreToolbar.tsx

+21-15
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { inferResolvedUriFromRelativePath } from "core/util/ideUtils";
33
import { debounce } from "lodash";
44
import { useContext, useEffect, useRef, useState } from "react";
55
import styled from "styled-components";
6-
import { v4 as uuidv4 } from "uuid";
76
import {
87
defaultBorderRadius,
98
vscCommandCenterInactiveBorder,
@@ -52,17 +51,18 @@ export interface StepContainerPreToolbarProps {
5251
relativeFilepath: string;
5352
isGeneratingCodeBlock: boolean;
5453
codeBlockIndex: number; // To track which codeblock we are applying
54+
codeBlockStreamId: string;
5555
range?: string;
5656
children: any;
5757
expanded?: boolean;
5858
hideApply?: boolean;
59+
autoApply?: boolean;
5960
}
6061

6162
export default function StepContainerPreToolbar(
6263
props: StepContainerPreToolbarProps,
6364
) {
6465
const ideMessenger = useContext(IdeMessengerContext);
65-
const streamIdRef = useRef<string>(uuidv4());
6666
const wasGeneratingRef = useRef(props.isGeneratingCodeBlock);
6767
const isInEditMode = useAppSelector(selectIsInEditMode);
6868
const [isExpanded, setIsExpanded] = useState(
@@ -76,7 +76,7 @@ export default function StepContainerPreToolbar(
7676
);
7777

7878
const applyState = useAppSelector((state) =>
79-
selectApplyStateByStreamId(state, streamIdRef.current),
79+
selectApplyStateByStreamId(state, props.codeBlockStreamId),
8080
);
8181

8282
// This handles an edge case when the last node in the markdown syntax tree is a codeblock.
@@ -104,7 +104,7 @@ export default function StepContainerPreToolbar(
104104
);
105105

106106
ideMessenger.post("applyToFile", {
107-
streamId: streamIdRef.current,
107+
streamId: props.codeBlockStreamId,
108108
filepath: fileUri,
109109
text: codeBlockContent,
110110
curSelectedModelTitle: defaultModel.title,
@@ -135,19 +135,25 @@ export default function StepContainerPreToolbar(
135135
}
136136
}, [props.children, codeBlockContent]);
137137

138-
// Temporarily disabling auto apply for Edit mode
139138
// useEffect(() => {
140139
// const hasCompletedGenerating =
141140
// wasGeneratingRef.current && !isGeneratingCodeBlock;
142-
143-
// const shouldAutoApply = hasCompletedGenerating && isInEditMode;
144-
145-
// if (shouldAutoApply) {
146-
// onClickApply();
147-
// }
148-
141+
// console.log(
142+
// wasGeneratingRef.current,
143+
// isGeneratingCodeBlock,
144+
// props.autoApply,
145+
// );
149146
// wasGeneratingRef.current = isGeneratingCodeBlock;
150-
// }, [isGeneratingCodeBlock]);
147+
// if (hasCompletedGenerating) {
148+
// console.log("Completed generating", props.autoApply);
149+
// if (props.autoApply) {
150+
// onClickApply();
151+
// }
152+
// // else if(isInEditMode) {
153+
// // onClickApply();
154+
// // }
155+
// }
156+
// }, [wasGeneratingRef, isGeneratingCodeBlock, props.autoApply]);
151157

152158
async function onClickAcceptApply() {
153159
const fileUri = await inferResolvedUriFromRelativePath(
@@ -156,7 +162,7 @@ export default function StepContainerPreToolbar(
156162
);
157163
ideMessenger.post("acceptDiff", {
158164
filepath: fileUri,
159-
streamId: streamIdRef.current,
165+
streamId: props.codeBlockStreamId,
160166
});
161167
}
162168

@@ -167,7 +173,7 @@ export default function StepContainerPreToolbar(
167173
);
168174
ideMessenger.post("rejectDiff", {
169175
filepath: fileUri,
170-
streamId: streamIdRef.current,
176+
streamId: props.codeBlockStreamId,
171177
});
172178
}
173179

gui/src/components/markdown/StyledMarkdownPreview.tsx

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ctxItemToRifWithContents } from "core/commands/util";
2-
import { memo, useEffect, useMemo } from "react";
2+
import { memo, useEffect, useMemo, useRef } from "react";
33
import { useRemark } from "react-remark";
44
import rehypeHighlight, { Options } from "rehype-highlight";
55
import rehypeKatex from "rehype-katex";
@@ -196,6 +196,10 @@ const StyledMarkdownPreview = memo(function StyledMarkdownPreview(
196196
}, [props.itemIndex, history, allSymbols]);
197197
const pastFileInfoRef = useUpdatingRef(pastFileInfo);
198198

199+
const codeblockState = useRef<{ streamId: string; isGenerating: boolean }[]>(
200+
[],
201+
);
202+
199203
const [reactContent, setMarkdownSource] = useRemark({
200204
remarkPlugins: [
201205
remarkTables,
@@ -282,8 +286,6 @@ const StyledMarkdownPreview = memo(function StyledMarkdownPreview(
282286
const { className, range } = preChildProps;
283287
const relativeFilePath = preChildProps["data-relativefilepath"];
284288
const codeBlockContent = preChildProps["data-codeblockcontent"];
285-
const isGeneratingCodeBlock =
286-
preChildProps["data-isgeneratingcodeblock"];
287289

288290
if (!props.isRenderingInStepContainer) {
289291
return <SyntaxHighlightedPre {...preProps} />;
@@ -307,6 +309,18 @@ const StyledMarkdownPreview = memo(function StyledMarkdownPreview(
307309
);
308310
}
309311

312+
const isGeneratingCodeBlock =
313+
preChildProps["data-isgeneratingcodeblock"];
314+
315+
if (codeblockState.current[codeBlockIndex] === undefined) {
316+
codeblockState.current[codeBlockIndex] = {
317+
streamId: uuidv4(),
318+
isGenerating: isGeneratingCodeBlock,
319+
};
320+
}
321+
const codeblockStreamId =
322+
codeblockState.current[codeBlockIndex].streamId;
323+
310324
// We use a custom toolbar for codeblocks in the step container
311325
return (
312326
<StepContainerPreToolbar
@@ -316,6 +330,8 @@ const StyledMarkdownPreview = memo(function StyledMarkdownPreview(
316330
relativeFilepath={relativeFilePath}
317331
isGeneratingCodeBlock={isGeneratingCodeBlock}
318332
range={range}
333+
autoApply={false}
334+
codeBlockStreamId={codeblockStreamId}
319335
>
320336
<SyntaxHighlightedPre {...preProps} />
321337
</StepContainerPreToolbar>

gui/src/redux/slices/uiSlice.ts

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const uiSlice = createSlice({
4545
ttsActive: false,
4646
toolSettings: {
4747
[BuiltInToolNames.ReadFile]: "allowedWithoutPermission",
48+
[BuiltInToolNames.EditExistingFile]: "allowedWithPermission",
4849
[BuiltInToolNames.CreateNewFile]: "allowedWithPermission",
4950
[BuiltInToolNames.RunTerminalCommand]: "allowedWithPermission",
5051
[BuiltInToolNames.ViewSubdirectory]: "allowedWithoutPermission",

0 commit comments

Comments
 (0)