fix(chat): remove regenerate action
This commit is contained in:
@@ -15,7 +15,6 @@ import {
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import ContentCopyRounded from "@mui/icons-material/ContentCopyRounded";
|
||||
import RefreshRounded from "@mui/icons-material/RefreshRounded";
|
||||
import { TbArrowsSplit2 } from "react-icons/tb";
|
||||
import type { PermissionReply } from "@/lib/chatStream";
|
||||
import {
|
||||
@@ -46,7 +45,6 @@ type AgentTurnProps = {
|
||||
onResume: () => void;
|
||||
onStopSpeech: () => void;
|
||||
isTtsSupported: boolean;
|
||||
onRegenerate: (messageId: string) => void;
|
||||
onCreateBranch: (messageId: string) => void;
|
||||
onReplyPermission: (requestId: string, reply: PermissionReply) => void;
|
||||
onReplyQuestion: (requestId: string, answers: string[][]) => void;
|
||||
@@ -62,7 +60,6 @@ export const AgentTurn = React.memo(
|
||||
onResume,
|
||||
onStopSpeech,
|
||||
isTtsSupported,
|
||||
onRegenerate,
|
||||
onCreateBranch,
|
||||
onReplyPermission,
|
||||
onReplyQuestion,
|
||||
@@ -316,18 +313,6 @@ export const AgentTurn = React.memo(
|
||||
<ContentCopyRounded sx={{ fontSize: 16 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="重新生成">
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label="重新生成"
|
||||
onClick={() => {
|
||||
onRegenerate(message.id);
|
||||
}}
|
||||
sx={{ width: 28, height: 28, color: "text.secondary", "&:hover": { color: "#00acc1", bgcolor: alpha("#00acc1", 0.1) } }}
|
||||
>
|
||||
<RefreshRounded sx={{ fontSize: 16 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="拆分为新会话">
|
||||
<IconButton
|
||||
size="small"
|
||||
|
||||
@@ -41,7 +41,6 @@ describe("AgentWorkspace", () => {
|
||||
onResumeSpeech: jest.fn(),
|
||||
onStopSpeech: jest.fn(),
|
||||
isTtsSupported: false,
|
||||
onRegenerate: jest.fn(),
|
||||
onCreateBranch: jest.fn(),
|
||||
onReplyPermission: jest.fn(),
|
||||
onReplyQuestion: jest.fn(),
|
||||
|
||||
@@ -28,7 +28,6 @@ type AgentWorkspaceProps = {
|
||||
onResumeSpeech: () => void;
|
||||
onStopSpeech: () => void;
|
||||
isTtsSupported: boolean;
|
||||
onRegenerate: (messageId: string) => void;
|
||||
onCreateBranch: (messageId: string) => void;
|
||||
onReplyPermission: (requestId: string, reply: PermissionReply) => void;
|
||||
onReplyQuestion: (requestId: string, answers: string[][]) => void;
|
||||
@@ -44,7 +43,6 @@ type TurnListProps = {
|
||||
onResumeSpeech: () => void;
|
||||
onStopSpeech: () => void;
|
||||
isTtsSupported: boolean;
|
||||
onRegenerate: (messageId: string) => void;
|
||||
onCreateBranch: (messageId: string) => void;
|
||||
onReplyPermission: (requestId: string, reply: PermissionReply) => void;
|
||||
onReplyQuestion: (requestId: string, answers: string[][]) => void;
|
||||
@@ -64,7 +62,6 @@ const TurnListInner = ({
|
||||
onResumeSpeech,
|
||||
onStopSpeech,
|
||||
isTtsSupported,
|
||||
onRegenerate,
|
||||
onCreateBranch,
|
||||
onReplyPermission,
|
||||
onReplyQuestion,
|
||||
@@ -82,7 +79,6 @@ const TurnListInner = ({
|
||||
onResume={onResumeSpeech}
|
||||
onStopSpeech={onStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onRegenerate={onRegenerate}
|
||||
onCreateBranch={onCreateBranch}
|
||||
onReplyPermission={onReplyPermission}
|
||||
onReplyQuestion={onReplyQuestion}
|
||||
@@ -104,7 +100,6 @@ const TurnList = React.memo(
|
||||
prevProps.onResumeSpeech === nextProps.onResumeSpeech &&
|
||||
prevProps.onStopSpeech === nextProps.onStopSpeech &&
|
||||
prevProps.isTtsSupported === nextProps.isTtsSupported &&
|
||||
prevProps.onRegenerate === nextProps.onRegenerate &&
|
||||
prevProps.onCreateBranch === nextProps.onCreateBranch &&
|
||||
prevProps.onReplyPermission === nextProps.onReplyPermission &&
|
||||
prevProps.onReplyQuestion === nextProps.onReplyQuestion &&
|
||||
@@ -238,7 +233,6 @@ export const AgentWorkspace = ({
|
||||
onResumeSpeech,
|
||||
onStopSpeech,
|
||||
isTtsSupported,
|
||||
onRegenerate,
|
||||
onCreateBranch,
|
||||
onReplyPermission,
|
||||
onReplyQuestion,
|
||||
@@ -287,7 +281,6 @@ export const AgentWorkspace = ({
|
||||
onResumeSpeech={onResumeSpeech}
|
||||
onStopSpeech={onStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onRegenerate={onRegenerate}
|
||||
onCreateBranch={onCreateBranch}
|
||||
onReplyPermission={onReplyPermission}
|
||||
onReplyQuestion={onReplyQuestion}
|
||||
@@ -304,7 +297,6 @@ export const AgentWorkspace = ({
|
||||
onResumeSpeech={onResumeSpeech}
|
||||
onStopSpeech={onStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onRegenerate={onRegenerate}
|
||||
onCreateBranch={onCreateBranch}
|
||||
onReplyPermission={onReplyPermission}
|
||||
onReplyQuestion={onReplyQuestion}
|
||||
|
||||
@@ -71,7 +71,6 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
|
||||
isStreaming,
|
||||
sessionTitle,
|
||||
sendPrompt,
|
||||
regenerate,
|
||||
createBranch,
|
||||
abort,
|
||||
replyPermission,
|
||||
@@ -352,7 +351,6 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
|
||||
onResumeSpeech={handleResumeSpeech}
|
||||
onStopSpeech={handleStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onRegenerate={regenerate}
|
||||
onCreateBranch={createBranch}
|
||||
onReplyPermission={replyPermission}
|
||||
onReplyQuestion={replyQuestion}
|
||||
|
||||
@@ -359,84 +359,6 @@ describe("useAgentChatSession actions", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("asks the backend to undo the previous user turn before regenerating", async () => {
|
||||
listChatSessions.mockResolvedValue([]);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useAgentChatSession({
|
||||
projectId: "project-1",
|
||||
onToolCall: jest.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
await waitFor(() => expect(result.current.isHydrating).toBe(false));
|
||||
|
||||
await act(async () => {
|
||||
await result.current.sendPrompt("重新分析压力异常");
|
||||
});
|
||||
const assistantMessageId = result.current.messages[1]?.id ?? "";
|
||||
|
||||
await act(async () => {
|
||||
await result.current.regenerate(assistantMessageId);
|
||||
});
|
||||
|
||||
expect(streamAgentChat).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({
|
||||
message: "重新分析压力异常",
|
||||
regenerateFromMessageIndex: 0,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("replaces the current chain when regenerating a middle assistant message", async () => {
|
||||
listChatSessions.mockResolvedValue([]);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useAgentChatSession({
|
||||
projectId: "project-1",
|
||||
onToolCall: jest.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
await waitFor(() => expect(result.current.isHydrating).toBe(false));
|
||||
|
||||
await act(async () => {
|
||||
await result.current.sendPrompt("第一轮");
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await result.current.sendPrompt("第二轮");
|
||||
});
|
||||
|
||||
const firstAssistantMessageId = result.current.messages[1]?.id ?? "";
|
||||
|
||||
await act(async () => {
|
||||
await result.current.regenerate(firstAssistantMessageId);
|
||||
});
|
||||
|
||||
expect(result.current.messages).toHaveLength(2);
|
||||
expect(result.current.messages[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
role: "user",
|
||||
content: "第一轮",
|
||||
}),
|
||||
);
|
||||
expect(result.current.messages[1]).toEqual(
|
||||
expect.objectContaining({
|
||||
role: "assistant",
|
||||
content: "",
|
||||
}),
|
||||
);
|
||||
expect(streamAgentChat).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
expect.objectContaining({
|
||||
message: "第一轮",
|
||||
regenerateFromMessageIndex: 0,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("forks a copied conversation from an assistant message", async () => {
|
||||
listChatSessions.mockResolvedValue([]);
|
||||
|
||||
|
||||
@@ -407,7 +407,6 @@ export const useAgentChatSession = ({
|
||||
async ({
|
||||
prompt: rawPrompt,
|
||||
sessionIdOverride,
|
||||
regenerateFromMessageIndex,
|
||||
preparedMessages,
|
||||
userMessage,
|
||||
assistantMessage,
|
||||
@@ -442,7 +441,6 @@ export const useAgentChatSession = ({
|
||||
sessionId: sessionIdOverride ?? sessionIdRef.current,
|
||||
model: getModel?.(),
|
||||
approvalMode: getApprovalMode?.(),
|
||||
regenerateFromMessageIndex,
|
||||
signal: controller.signal,
|
||||
onEvent: (event) =>
|
||||
applyStreamEvent(event, {
|
||||
@@ -893,43 +891,6 @@ export const useAgentChatSession = ({
|
||||
[isHydrating, messages],
|
||||
);
|
||||
|
||||
const regenerate = useCallback(async (messageId: string) => {
|
||||
if (isHydrating || isStreaming || messages.length === 0) return;
|
||||
|
||||
const targetAssistantIndex = messages.findIndex(
|
||||
(message) => message.id === messageId && message.role === "assistant",
|
||||
);
|
||||
if (targetAssistantIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let targetUserIndex = targetAssistantIndex - 1;
|
||||
while (targetUserIndex >= 0 && messages[targetUserIndex].role !== "user") {
|
||||
targetUserIndex--;
|
||||
}
|
||||
|
||||
if (targetUserIndex < 0) return;
|
||||
|
||||
const targetUser = messages[targetUserIndex];
|
||||
const targetUserContent = targetUser.content;
|
||||
const nextMessages = cloneMessages(messages.slice(0, targetUserIndex));
|
||||
const nextUserMessage = createUserMessage(targetUserContent);
|
||||
const nextAssistantMessage = createAssistantMessage();
|
||||
|
||||
setMessages(nextMessages);
|
||||
await runPrompt({
|
||||
prompt: targetUserContent,
|
||||
regenerateFromMessageIndex: targetUserIndex,
|
||||
preparedMessages: [
|
||||
...nextMessages,
|
||||
nextUserMessage,
|
||||
nextAssistantMessage,
|
||||
],
|
||||
userMessage: nextUserMessage,
|
||||
assistantMessage: nextAssistantMessage,
|
||||
});
|
||||
}, [isHydrating, isStreaming, messages, runPrompt]);
|
||||
|
||||
const createBranch = useCallback(
|
||||
async (messageId: string) => {
|
||||
if (isHydrating || isStreaming) return;
|
||||
@@ -975,7 +936,6 @@ export const useAgentChatSession = ({
|
||||
sessionTitle,
|
||||
sessionId,
|
||||
sendPrompt,
|
||||
regenerate,
|
||||
createBranch,
|
||||
abort,
|
||||
replyPermission,
|
||||
|
||||
@@ -18,7 +18,6 @@ export type UseAgentChatSessionOptions = {
|
||||
export type PromptRunOptions = {
|
||||
prompt: string;
|
||||
sessionIdOverride?: string;
|
||||
regenerateFromMessageIndex?: number;
|
||||
preparedMessages?: Message[];
|
||||
userMessage?: Message;
|
||||
assistantMessage?: Message;
|
||||
|
||||
@@ -75,7 +75,6 @@ describe("streamAgentChat", () => {
|
||||
session_id: undefined,
|
||||
model: "deepseek/deepseek-v4-pro",
|
||||
approval_mode: undefined,
|
||||
regenerate_from_message_index: undefined,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -140,7 +140,6 @@ type StreamOptions = {
|
||||
sessionId?: string;
|
||||
model?: AgentModel;
|
||||
approvalMode?: AgentApprovalMode;
|
||||
regenerateFromMessageIndex?: number;
|
||||
signal?: AbortSignal;
|
||||
onEvent: (event: StreamEvent) => void;
|
||||
};
|
||||
@@ -460,7 +459,6 @@ export const streamAgentChat = async ({
|
||||
sessionId,
|
||||
model,
|
||||
approvalMode,
|
||||
regenerateFromMessageIndex,
|
||||
signal,
|
||||
onEvent,
|
||||
}: StreamOptions) => {
|
||||
@@ -480,7 +478,6 @@ export const streamAgentChat = async ({
|
||||
session_id: sessionId,
|
||||
model,
|
||||
approval_mode: approvalMode,
|
||||
regenerate_from_message_index: regenerateFromMessageIndex,
|
||||
}),
|
||||
projectHeaderMode: "include",
|
||||
userHeaderMode: "include",
|
||||
|
||||
Reference in New Issue
Block a user