redo reverts code (when possible) (#75)
This commit is contained in:
@@ -53,6 +53,7 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "../ui/tooltip";
|
} from "../ui/tooltip";
|
||||||
import { useNavigate } from "@tanstack/react-router";
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
|
import { useVersions } from "@/hooks/useVersions";
|
||||||
|
|
||||||
const showTokenBarAtom = atom(false);
|
const showTokenBarAtom = atom(false);
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
const [inputValue, setInputValue] = useAtom(chatInputValueAtom);
|
const [inputValue, setInputValue] = useAtom(chatInputValueAtom);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
const { settings, updateSettings, isAnyProviderSetup } = useSettings();
|
const { settings, updateSettings, isAnyProviderSetup } = useSettings();
|
||||||
|
const appId = useAtomValue(selectedAppIdAtom);
|
||||||
|
const { refreshVersions } = useVersions(appId);
|
||||||
const { streamMessage, isStreaming, setIsStreaming, error, setError } =
|
const { streamMessage, isStreaming, setIsStreaming, error, setError } =
|
||||||
useStreamChat();
|
useStreamChat();
|
||||||
const [showError, setShowError] = useState(true);
|
const [showError, setShowError] = useState(true);
|
||||||
@@ -162,6 +165,7 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
} finally {
|
} finally {
|
||||||
setIsApproving(false);
|
setIsApproving(false);
|
||||||
setIsPreviewOpen(true);
|
setIsPreviewOpen(true);
|
||||||
|
refreshVersions();
|
||||||
|
|
||||||
// Keep same as handleReject
|
// Keep same as handleReject
|
||||||
refreshProposal();
|
refreshProposal();
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { selectedChatIdAtom } from "@/atoms/chatAtoms";
|
|||||||
import { useAtom, useAtomValue } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { RefreshCw } from "lucide-react";
|
import { RefreshCw } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { useVersions } from "@/hooks/useVersions";
|
||||||
|
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
||||||
|
import { showError } from "@/lib/toast";
|
||||||
|
|
||||||
interface MessagesListProps {
|
interface MessagesListProps {
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
@@ -17,6 +20,8 @@ interface MessagesListProps {
|
|||||||
|
|
||||||
export const MessagesList = forwardRef<HTMLDivElement, MessagesListProps>(
|
export const MessagesList = forwardRef<HTMLDivElement, MessagesListProps>(
|
||||||
function MessagesList({ messages, messagesEndRef }, ref) {
|
function MessagesList({ messages, messagesEndRef }, ref) {
|
||||||
|
const appId = useAtomValue(selectedAppIdAtom);
|
||||||
|
const { versions, revertVersion } = useVersions(appId);
|
||||||
const { streamMessage, isStreaming, error, setError } = useStreamChat();
|
const { streamMessage, isStreaming, error, setError } = useStreamChat();
|
||||||
const { isAnyProviderSetup } = useSettings();
|
const { isAnyProviderSetup } = useSettings();
|
||||||
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
||||||
@@ -39,11 +44,42 @@ export const MessagesList = forwardRef<HTMLDivElement, MessagesListProps>(
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
if (!selectedChatId) {
|
if (!selectedChatId) {
|
||||||
console.error("No chat selected");
|
console.error("No chat selected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// The last message is usually an assistant, but it might not be.
|
||||||
|
const lastVersion = versions[0];
|
||||||
|
const lastMessage = messages[messages.length - 1];
|
||||||
|
let reverted = false;
|
||||||
|
if (
|
||||||
|
lastVersion.oid === lastMessage.commitHash &&
|
||||||
|
lastMessage.role === "assistant"
|
||||||
|
) {
|
||||||
|
if (versions.length < 2) {
|
||||||
|
showError("Cannot retry message; no previous version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const previousAssistantMessage =
|
||||||
|
messages[messages.length - 3];
|
||||||
|
if (
|
||||||
|
previousAssistantMessage?.role === "assistant" &&
|
||||||
|
previousAssistantMessage?.commitHash
|
||||||
|
) {
|
||||||
|
console.debug("Reverting to previous assistant version");
|
||||||
|
await revertVersion({
|
||||||
|
versionId: previousAssistantMessage.commitHash,
|
||||||
|
});
|
||||||
|
reverted = true;
|
||||||
|
} else {
|
||||||
|
console.debug("Reverting to previous version");
|
||||||
|
await revertVersion({
|
||||||
|
versionId: versions[1].oid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the last user message
|
// Find the last user message
|
||||||
const lastUserMessage = [...messages]
|
const lastUserMessage = [...messages]
|
||||||
.reverse()
|
.reverse()
|
||||||
@@ -52,10 +88,15 @@ export const MessagesList = forwardRef<HTMLDivElement, MessagesListProps>(
|
|||||||
console.error("No user message found");
|
console.error("No user message found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// If we reverted, we don't need to mark "redo" because
|
||||||
|
// the old message has already been deleted.
|
||||||
|
const redo = !reverted;
|
||||||
|
console.debug("Streaming message with redo", redo);
|
||||||
|
|
||||||
streamMessage({
|
streamMessage({
|
||||||
prompt: lastUserMessage.content,
|
prompt: lastUserMessage.content,
|
||||||
chatId: selectedChatId,
|
chatId: selectedChatId,
|
||||||
redo: true,
|
redo,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -494,6 +494,7 @@ export function registerAppHandlers() {
|
|||||||
_,
|
_,
|
||||||
{ appId, previousVersionId }: { appId: number; previousVersionId: string }
|
{ appId, previousVersionId }: { appId: number; previousVersionId: string }
|
||||||
) => {
|
) => {
|
||||||
|
logger.log(`Reverting to version ${previousVersionId} for app ${appId}`);
|
||||||
return withLock(appId, async () => {
|
return withLock(appId, async () => {
|
||||||
const app = await db.query.apps.findFirst({
|
const app = await db.query.apps.findFirst({
|
||||||
where: eq(apps.id, appId),
|
where: eq(apps.id, appId),
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export interface Message {
|
|||||||
role: "user" | "assistant";
|
role: "user" | "assistant";
|
||||||
content: string;
|
content: string;
|
||||||
approvalState?: "approved" | "rejected" | null;
|
approvalState?: "approved" | "rejected" | null;
|
||||||
|
commitHash?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Chat {
|
export interface Chat {
|
||||||
|
|||||||
Reference in New Issue
Block a user