Files
paseo/packages/app/src/components/rewind/use-rewind-agent-mutation.ts

77 lines
2.5 KiB
TypeScript

import { useCallback } from "react";
import { useTranslation } from "react-i18next";
import { useMutation } from "@tanstack/react-query";
import { useToast } from "@/contexts/toast-context";
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
import type { RewindMode } from "./use-rewind-capabilities";
import { useRewindComposerRestore } from "./composer-restore";
import { useSessionStore } from "@/stores/session-store";
import { shouldRestoreComposerForRewindMode } from "./rewind-mode";
import { getHostRuntimeStore } from "@/runtime/host-runtime";
interface UseRewindAgentMutationInput {
serverId?: string;
agentId?: string;
messageId?: string;
client?: DaemonClient | null;
}
interface RewindAgentInput {
mode: RewindMode;
rewoundText: string;
}
export function useRewindAgentMutation(input: UseRewindAgentMutationInput): {
rewindAgent: (input: RewindAgentInput) => Promise<void>;
isPending: boolean;
} {
const toast = useToast();
const { t } = useTranslation();
const composerRestore = useRewindComposerRestore();
const { isPending, mutateAsync } = useMutation({
mutationFn: async ({ mode }: RewindAgentInput) => {
if (!input.client || !input.agentId || !input.messageId) {
throw new Error(t("common.errors.daemonClientUnavailable"));
}
await input.client.rewindAgent(input.agentId, input.messageId, mode);
if (mode !== "files") {
const cursor = input.serverId
? useSessionStore
.getState()
.sessions[input.serverId]?.agentTimelineCursor.get(input.agentId)
: undefined;
if (!input.serverId) throw new Error(t("common.errors.daemonClientUnavailable"));
await getHostRuntimeStore().fetchAgentTimeline(input.serverId, input.agentId, {
direction: "tail",
projection: "projected",
...(cursor ? { cursor: { epoch: cursor.epoch, seq: cursor.endSeq } } : {}),
});
}
},
onSuccess: (_data, variables) => {
if (!shouldRestoreComposerForRewindMode(variables.mode)) {
return;
}
composerRestore?.restoreTextIfComposerEmpty(variables.rewoundText);
},
onError: (error) => {
toast.error(error instanceof Error ? error.message : t("rewind.errors.failed"));
},
});
const rewindAgent = useCallback(
async (rewindInput: RewindAgentInput) => {
if (isPending) {
return;
}
await mutateAsync(rewindInput);
},
[isPending, mutateAsync],
);
return {
rewindAgent,
isPending,
};
}