Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f083767
ui(patches): remove apply and replace buttons and make the code revea…
MarcMcIntosh Feb 20, 2025
59763a5
ui(new patches): remove new event for sending a patchto the ide.
MarcMcIntosh Feb 20, 2025
e742f85
wip(ide tool edit): send enough info to the ide to know which tool ed…
MarcMcIntosh Feb 21, 2025
93cab57
feat(chat): append tool call accepted message to chat when the user a…
MarcMcIntosh Feb 21, 2025
f4f8cdc
wip(manual patch): remove the tool confiormation when manually applyi…
MarcMcIntosh Feb 21, 2025
b775f17
fix: inconstancy with auto sending when accpetting or reject a patch …
MarcMcIntosh Feb 21, 2025
f983fb4
fix(updating tool messages): handle multi model.
MarcMcIntosh Feb 21, 2025
d4b8b31
remove unused import.
MarcMcIntosh Feb 21, 2025
2c298f7
fix(apply): auto calls when user manually presses apply then accept/r…
MarcMcIntosh Feb 21, 2025
e838ee9
fix(apply confirmation): add the correct message if the user accepts …
MarcMcIntosh Feb 24, 2025
342413e
fix(acceot / reject): prevent sending message no rejection.
MarcMcIntosh Feb 24, 2025
429d2b7
fix(upsertToolCall): import the action in the thread reducer.
MarcMcIntosh Feb 24, 2025
7ba3a6b
fix: don't continue streaming if the user rejects the tool use.
MarcMcIntosh Feb 24, 2025
d4cee1b
ui(confirmation): remove loading dots.
MarcMcIntosh Feb 24, 2025
4a3120b
ui(markdown): remove custom stye for update textdoc
MarcMcIntosh Feb 24, 2025
20d1aef
ci: update version bump logic for alpha branch & npm publish in CI (#…
alashchev17 Feb 23, 2025
5cdc0d7
refactor: use git2 status show instead of redundant enum, allow to ge…
humbertoyusta Feb 20, 2025
e6f4a04
uncommited changes warning message separating unstaged and staged
humbertoyusta Feb 20, 2025
c655fc7
remove unused method
humbertoyusta Feb 20, 2025
26d345e
fix: uncommited changes warning, failed integrations links and more s…
humbertoyusta Feb 21, 2025
923fbbb
fix: add usage also for delta collector in streaming in python sdk
humbertoyusta Feb 21, 2025
6441cfb
fix: count cache tokens for claude
humbertoyusta Feb 21, 2025
fb04e30
fix: increase stream limit
humbertoyusta Feb 21, 2025
3fbf5cd
fix: secrets yaml was not used
humbertoyusta Feb 24, 2025
94622b7
ci(npm publish): better version bump message (#523)
alashchev17 Feb 24, 2025
a5cec42
fix: showing usable models if user's plan is not FREE (#522)
alashchev17 Feb 24, 2025
369b014
feat: version bump [email protected] (#525)
alashchev17 Feb 24, 2025
9ac63b2
feat: version bump [email protected] (#526)
alashchev17 Feb 24, 2025
e626d51
fix(chat): remove unused import.
MarcMcIntosh Feb 24, 2025
555a2b5
Merge 'main' into 'dev' (#529)
alashchev17 Feb 24, 2025
12702fd
Merge branch 'dev-2' into ui-patch-tool-changes
MarcMcIntosh Feb 24, 2025
9da93fe
copy .github/workflows/agent_gui_npm_publish.yml from main
MarcMcIntosh Feb 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion refact-agent/gui/src/app/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
restoreChat,
newIntegrationChat,
chatResponse,
setIsWaitingForResponse,
upsertToolCall,
} from "../features/Chat/Thread";
import { statisticsApi } from "../services/refact/statistics";
import { integrationsApi } from "../services/refact/integrations";
Expand All @@ -31,7 +33,11 @@ import { resetAttachedImagesSlice } from "../features/AttachedImages";
import { nextTip } from "../features/TipOfTheDay";
import { telemetryApi } from "../services/refact/telemetry";
import { CONFIG_PATH_URL, FULL_PATH_URL } from "../services/refact/consts";
import { resetConfirmationInteractedState } from "../features/ToolConfirmation/confirmationSlice";
import {
clearPauseReasonsAndHandleToolsStatus,
resetConfirmationInteractedState,
updateConfirmationAfterIdeToolUse,
} from "../features/ToolConfirmation/confirmationSlice";
import {
getAgentUsageCounter,
getMaxFreeAgentUsage,
Expand All @@ -40,6 +46,8 @@ import {
updateAgentUsage,
updateMaxAgentUsageAmount,
} from "../features/AgentUsage/agentUsageSlice";
import { ideToolCallResponse } from "../hooks/useEventBusForIDE";
import { upsertToolCallIntoHistory } from "../features/History/historySlice";

const AUTH_ERROR_MESSAGE =
"There is an issue with your API key. Check out your API Key or re-login";
Expand Down Expand Up @@ -496,3 +504,35 @@ startListening({
}
},
});

// Tool Call results from ide.
startListening({
actionCreator: ideToolCallResponse,
effect: (action, listenerApi) => {
const state = listenerApi.getState();

const toolCallUpsertPayload = {
...action.payload,
replaceOnly: !!action.payload.accepted,
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stop on reject, continue on accept

listenerApi.dispatch(upsertToolCallIntoHistory(toolCallUpsertPayload));
listenerApi.dispatch(upsertToolCall(toolCallUpsertPayload));

listenerApi.dispatch(updateConfirmationAfterIdeToolUse(action.payload));

const pauseReasons = state.confirmation.pauseReasons.filter(
(reason) => reason.tool_call_id !== action.payload.toolCallId,
);

if (pauseReasons.length === 0) {
listenerApi.dispatch(
clearPauseReasonsAndHandleToolsStatus({
wasInteracted: true,
confirmationStatus: !!action.payload.accepted,
}),
);
listenerApi.dispatch(setIsWaitingForResponse(false));
}
},
});
4 changes: 3 additions & 1 deletion refact-agent/gui/src/components/ChatContent/ChatContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { popBackTo } from "../../features/Pages/pagesSlice";
import { ChatLinks, UncommittedChangesWarning } from "../ChatLinks";
import { telemetryApi } from "../../services/refact/telemetry";
import { PlaceHolderText } from "./PlaceHolderText";
import { getConfirmationPauseStatus } from "../../features/ToolConfirmation/confirmationSlice";

export type ChatContentProps = {
onRetry: (index: number, question: UserMessage["content"]) => void;
Expand All @@ -52,6 +53,7 @@ export const ChatContent: React.FC<ChatContentProps> = ({
const [sendTelemetryEvent] =
telemetryApi.useLazySendTelemetryChatEventQuery();
const integrationMeta = useAppSelector(selectIntegration);
const isWaitingForConfirmation = useAppSelector(getConfirmationPauseStatus);

const {
handleScroll,
Expand Down Expand Up @@ -115,7 +117,7 @@ export const ChatContent: React.FC<ChatContentProps> = ({
<UncommittedChangesWarning />

<Container py="4">
<Spinner spinning={isWaiting} />
<Spinner spinning={isWaiting && !isWaitingForConfirmation} />
</Container>
</Flex>
{showFollowButton && (
Expand Down
14 changes: 9 additions & 5 deletions refact-agent/gui/src/components/ChatForm/ToolConfirmation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from "react";
import React, { useCallback, useMemo } from "react";
import {
PATCH_LIKE_FUNCTIONS,
useAppDispatch,
Expand Down Expand Up @@ -88,6 +88,10 @@ export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({
confirmToolUsage();
};

const handleReject = useCallback(() => {
rejectToolUsage(toolCallIds);
}, [rejectToolUsage, toolCallIds]);

const message = getConfirmationMessage(
commands,
rules,
Expand All @@ -101,7 +105,7 @@ export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({
return (
<PatchConfirmation
handleAllowForThisChat={handleAllowForThisChat}
rejectToolUsage={rejectToolUsage}
rejectToolUsage={handleReject}
confirmToolUsage={confirmToolUsage}
/>
);
Expand Down Expand Up @@ -167,9 +171,9 @@ export const ToolConfirmation: React.FC<ToolConfirmationProps> = ({
color="red"
variant="surface"
size="1"
onClick={rejectToolUsage}
onClick={handleReject}
>
Deny
Stop
</Button>
)}
</Flex>
Expand Down Expand Up @@ -258,7 +262,7 @@ const PatchConfirmation: React.FC<PatchConfirmationProps> = ({
size="1"
onClick={rejectToolUsage}
>
Deny
Stop
</Button>
</Flex>
</Flex>
Expand Down
10 changes: 2 additions & 8 deletions refact-agent/gui/src/components/Tools/Texdoc.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,9 @@
margin-top: 0;
}

:global(.radix-themes) .textdoc.textdoc__update :global(.hljs.language-diff) {
/* :global(.radix-themes) .textdoc.textdoc__update :global(.hljs.language-diff) {
--hlbg: var(--gray-3);
--hlcolor1: var(--gray-12);
/* --hlcolor2: #000000;
--hlcolor3: #000080;
--hlcolor4: #800080;
--hlcolor5: #808000;
--hlcolor6: #800000;
--hlcolor7: #0055af; */
--hlcolor8: var(--green-9);
--hlcolor9: var(--red-9);
}
Expand All @@ -44,4 +38,4 @@

.textdoc__update .textdoc__diffbox {
box-shadow: var(--shadow-1);
}
} */
85 changes: 54 additions & 31 deletions refact-agent/gui/src/components/Tools/Textdoc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import {
isUpdateTextDocToolCall,
parseRawTextDocToolCall,
} from "./types";
import { Box, Button, Card, Flex } from "@radix-ui/themes";
import { Box, Card, Flex, Button } from "@radix-ui/themes";
import { TruncateLeft } from "../Text";
import { Link } from "../Link";
import { useEventsBusForIDE } from "../../hooks/useEventBusForIDE";
import { Markdown } from "../Markdown";
import { filename } from "../../utils/filename";
import styles from "./Texdoc.module.css";
import { createPatch } from "diff";
import classNames from "classnames";
import { useCopyToClipboard } from "../../hooks/useCopyToClipboard";
import { Reveal } from "../Reveal";
import { useAppSelector } from "../../hooks";
import { selectCanPaste } from "../../features/Chat";
import { selectCanPaste, selectChatId } from "../../features/Chat";
import { toolsApi } from "../../services/refact";
import { ErrorCallout } from "../Callout";
import { isRTKResponseErrorWithDetailMessage } from "../../utils";
Expand Down Expand Up @@ -56,12 +56,14 @@ export const TextDocTool: React.FC<{ toolCall: RawTextDocTool }> = ({
const TextDocHeader: React.FC<{
toolCall: TextDocToolCall;
}> = ({ toolCall }) => {
const { openFile, diffPasteBack, sendToolEditToIde } = useEventsBusForIDE();
const { openFile, diffPasteBack, sendToolCallToIde } = useEventsBusForIDE();
const [requestDryRun, dryRunResult] = toolsApi.useDryRunForEditToolMutation();
const [errorMessage, setErrorMessage] = useState<string>("");
const canPaste = useAppSelector(selectCanPaste);
const chatId = useAppSelector(selectChatId);

const clearErrorMessage = useCallback(() => setErrorMessage(""), []);

// move this
const handleOpenFile = useCallback(() => {
if (!toolCall.function.arguments.path) return;
Expand All @@ -70,9 +72,9 @@ const TextDocHeader: React.FC<{

const handleReplace = useCallback(
(content: string) => {
diffPasteBack(content);
diffPasteBack(content, chatId, toolCall.id);
},
[diffPasteBack],
[chatId, diffPasteBack, toolCall.id],
);

const replaceContent = useMemo(() => {
Expand All @@ -90,7 +92,7 @@ const TextDocHeader: React.FC<{
})
.then((results) => {
if (results.data) {
sendToolEditToIde(toolCall.function.arguments.path, results.data);
sendToolCallToIde(toolCall, results.data, chatId);
} else if (isRTKResponseErrorWithDetailMessage(results)) {
setErrorMessage(results.error.data.detail);
}
Expand All @@ -107,12 +109,7 @@ const TextDocHeader: React.FC<{
setErrorMessage("Error with patch: " + JSON.stringify(error));
}
});
}, [
requestDryRun,
sendToolEditToIde,
toolCall.function.arguments,
toolCall.function.name,
]);
}, [chatId, requestDryRun, sendToolCallToIde, toolCall]);

return (
<Card size="1" variant="surface" mt="4" className={styles.textdoc__header}>
Expand Down Expand Up @@ -166,11 +163,17 @@ const CreateTextDoc: React.FC<{
"```" + extension + "\n" + toolCall.function.arguments.content + "\n```"
);
}, [toolCall.function.arguments.content, toolCall.function.arguments.path]);
const handleCopy = useCopyToClipboard();

const lineCount = useMemo(() => code.split("\n").length, [code]);

return (
// TODO: move this box up a bit, or make it generic
<Box className={styles.textdoc}>
<TextDocHeader toolCall={toolCall} />
<Markdown>{code}</Markdown>
<Reveal isRevealingCode defaultOpen={lineCount < 9}>
<Markdown onCopyClick={handleCopy}>{code}</Markdown>
</Reveal>
</Box>
);
};
Expand All @@ -191,11 +194,20 @@ const ReplaceTextDoc: React.FC<{
toolCall.function.arguments.path,
toolCall.function.arguments.replacement,
]);

const copyToClipBoard = useCopyToClipboard();
const handleCopy = useCallback(() => {
copyToClipBoard(toolCall.function.arguments.replacement);
}, [copyToClipBoard, toolCall.function.arguments.replacement]);

const lineCount = useMemo(() => code.split("\n").length, [code]);
return (
// TODO: move this box up a bit, or make it generic
<Box className={styles.textdoc}>
<TextDocHeader toolCall={toolCall} />
<Markdown>{code}</Markdown>
<Reveal isRevealingCode defaultOpen={lineCount < 9}>
<Markdown onCopyClick={handleCopy}>{code}</Markdown>
</Reveal>
</Box>
);
};
Expand All @@ -219,37 +231,48 @@ const UpdateRegexTextDoc: React.FC<{
toolCall.function.arguments.replacement,
]);

const lineCount = useMemo(() => code.split("\n").length, [code]);

return (
<Box className={styles.textdoc}>
<TextDocHeader toolCall={toolCall} />
<Markdown>{code}</Markdown>
<Reveal isRevealingCode defaultOpen={lineCount < 9}>
<Markdown>{code}</Markdown>
</Reveal>
</Box>
);
};

const UpdateTextDoc: React.FC<{
toolCall: UpdateTextDocToolCall;
}> = ({ toolCall }) => {
const diff = useMemo(() => {
const patch = createPatch(
toolCall.function.arguments.path,
toolCall.function.arguments.old_str,
toolCall.function.arguments.replacement,
const code = useMemo(() => {
const extension = getFileExtension(toolCall.function.arguments.path);
return (
"```" +
extension +
"\n" +
toolCall.function.arguments.replacement +
"\n```"
);

return "```diff\n" + patch + "\n```";
}, [
toolCall.function.arguments.replacement,
toolCall.function.arguments.old_str,
toolCall.function.arguments.path,
toolCall.function.arguments.replacement,
]);
// TODO: don't use markdown for this, it's two bright

const lineCount = useMemo(() => code.split("\n").length, [code]);

const copyToClipBoard = useCopyToClipboard();
const handleCopy = useCallback(() => {
copyToClipBoard(toolCall.function.arguments.replacement);
}, [copyToClipBoard, toolCall.function.arguments.replacement]);

return (
<Box className={classNames(styles.textdoc, styles.textdoc__update)}>
<Box className={styles.textdoc}>
<TextDocHeader toolCall={toolCall} />
<Box className={classNames(styles.textdoc__diffbox)}>
<Markdown useInlineStyles={false}>{diff}</Markdown>
</Box>
<Reveal isRevealingCode defaultOpen={lineCount < 9}>
<Markdown onCopyClick={handleCopy}>{code}</Markdown>
</Reveal>
</Box>
);
};
Expand Down
2 changes: 1 addition & 1 deletion refact-agent/gui/src/contexts/AbortControllers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const AbortControllerProvider: React.FC<{
const abort = (key: string, reason?: string) => {
if (key in abortControllers) {
const fn = abortControllers[key];
fn(reason);
fn(reason ?? "aborted");
removeController(key);
}
};
Expand Down
4 changes: 3 additions & 1 deletion refact-agent/gui/src/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export {
setCurrentProjectInfo,
type CurrentProjectInfo,
} from "../features/Chat/currentProject";
export type { TextDocToolCall } from "../components/Tools/types";

export type {
ToolCommand,
Expand Down Expand Up @@ -73,7 +74,8 @@ export {
ideEscapeKeyPressed,
ideIsChatStreaming,
ideIsChatReady,
ideToolEdit,
ideToolCall,
ideToolCallResponse,
} from "../hooks/useEventBusForIDE";

export const fim = {
Expand Down
5 changes: 5 additions & 0 deletions refact-agent/gui/src/features/Chat/Thread/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { ToolCommand } from "../../../services/refact/tools";
import { scanFoDuplicatesWith, takeFromEndWhile } from "../../../utils";
import { debugApp } from "../../../debugConfig";
import { ChatHistoryItem } from "../../History/historySlice";
import { ideToolCallResponse } from "../../../hooks/useEventBusForIDE";

export const newChatAction = createAction("chatThread/new");

Expand Down Expand Up @@ -144,6 +145,10 @@ export const fixBrokenToolMessages = createAction<PayloadWithId>(
"chatThread/fixBrokenToolMessages",
);

export const upsertToolCall = createAction<
Parameters<typeof ideToolCallResponse>[0] & { replaceOnly?: boolean }
>("chatThread/upsertToolCall");

// TODO: This is the circular dep when imported from hooks :/
const createAppAsyncThunk = createAsyncThunk.withTypes<{
state: RootState;
Expand Down
Loading