fix(chat): 重新生成前撤销旧消息
This commit is contained in:
@@ -251,7 +251,7 @@ export const AgentComposer = React.forwardRef<AgentComposerHandle, AgentComposer
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
<FormControl size="small" sx={{ minWidth: 102 }}>
|
<FormControl size="small" sx={{ minWidth: 96 }}>
|
||||||
<Select
|
<Select
|
||||||
value={approvalMode}
|
value={approvalMode}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@@ -260,13 +260,13 @@ export const AgentComposer = React.forwardRef<AgentComposerHandle, AgentComposer
|
|||||||
disabled={isHydrating || isStreaming}
|
disabled={isHydrating || isStreaming}
|
||||||
aria-label="权限批准模式"
|
aria-label="权限批准模式"
|
||||||
renderValue={(val) => (
|
renderValue={(val) => (
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
|
<Box sx={{ display: "flex", alignItems: "center", gap: 0.45 }}>
|
||||||
{val === "always" ? (
|
{val === "always" ? (
|
||||||
<AdminPanelSettingsRounded sx={{ fontSize: 16, color: "inherit" }} />
|
<AdminPanelSettingsRounded sx={{ fontSize: 18, color: "inherit" }} />
|
||||||
) : (
|
) : (
|
||||||
<VerifiedUserRounded sx={{ fontSize: 16, color: "inherit" }} />
|
<VerifiedUserRounded sx={{ fontSize: 18, color: "inherit" }} />
|
||||||
)}
|
)}
|
||||||
<Typography sx={{ fontSize: "0.78rem", fontWeight: 700, color: "inherit" }}>
|
<Typography sx={{ fontSize: "0.75rem", fontWeight: 600, color: "inherit" }}>
|
||||||
{val === "always" ? "始终允许" : "请求批准"}
|
{val === "always" ? "始终允许" : "请求批准"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -312,6 +312,7 @@ export const AgentComposer = React.forwardRef<AgentComposerHandle, AgentComposer
|
|||||||
py: 0,
|
py: 0,
|
||||||
pl: 1,
|
pl: 1,
|
||||||
pr: "28px !important",
|
pr: "28px !important",
|
||||||
|
minHeight: 36,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
@@ -326,14 +327,14 @@ export const AgentComposer = React.forwardRef<AgentComposerHandle, AgentComposer
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem value="request">
|
<MenuItem value="request">
|
||||||
<VerifiedUserRounded className="icon" sx={{ mr: 1.5, mt: 0.2, fontSize: 18, color: "text.secondary" }} />
|
<VerifiedUserRounded className="icon" sx={{ mr: 1.5, mt: 0.15, fontSize: 18, color: "text.secondary" }} />
|
||||||
<Box>
|
<Box>
|
||||||
<Typography className="title" sx={{ fontSize: "0.85rem", fontWeight: 700, color: "text.primary", mb: 0.2 }}>请求批准</Typography>
|
<Typography className="title" sx={{ fontSize: "0.85rem", fontWeight: 700, color: "text.primary", mb: 0.2 }}>请求批准</Typography>
|
||||||
<Typography sx={{ fontSize: "0.7rem", fontWeight: 500, color: "text.secondary", lineHeight: 1.3 }}>工具权限逐次确认</Typography>
|
<Typography sx={{ fontSize: "0.7rem", fontWeight: 500, color: "text.secondary", lineHeight: 1.3 }}>工具权限逐次确认</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value="always">
|
<MenuItem value="always">
|
||||||
<AdminPanelSettingsRounded className="icon" sx={{ mr: 1.5, mt: 0.2, fontSize: 18, color: "text.secondary" }} />
|
<AdminPanelSettingsRounded className="icon" sx={{ mr: 1.5, mt: 0.15, fontSize: 18, color: "text.secondary" }} />
|
||||||
<Box>
|
<Box>
|
||||||
<Typography className="title" sx={{ fontSize: "0.85rem", fontWeight: 700, color: "text.primary", mb: 0.2 }}>始终允许</Typography>
|
<Typography className="title" sx={{ fontSize: "0.85rem", fontWeight: 700, color: "text.primary", mb: 0.2 }}>始终允许</Typography>
|
||||||
<Typography sx={{ fontSize: "0.7rem", fontWeight: 500, color: "text.secondary", lineHeight: 1.3 }}>自动允许本轮权限请求</Typography>
|
<Typography sx={{ fontSize: "0.7rem", fontWeight: 500, color: "text.secondary", lineHeight: 1.3 }}>自动允许本轮权限请求</Typography>
|
||||||
|
|||||||
@@ -521,4 +521,33 @@ describe("useAgentChatSession", () => {
|
|||||||
expect.anything(),
|
expect.anything(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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("重新分析压力异常");
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await result.current.regenerate();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(streamAgentChat).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
expect.objectContaining({
|
||||||
|
message: "重新分析压力异常",
|
||||||
|
regenerateFromMessageIndex: 0,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ type UseAgentChatSessionOptions = {
|
|||||||
type PromptRunOptions = {
|
type PromptRunOptions = {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
sessionIdOverride?: string;
|
sessionIdOverride?: string;
|
||||||
|
regenerateFromMessageIndex?: number;
|
||||||
preparedMessages?: Message[];
|
preparedMessages?: Message[];
|
||||||
userMessage?: Message;
|
userMessage?: Message;
|
||||||
assistantMessage?: Message;
|
assistantMessage?: Message;
|
||||||
@@ -609,6 +610,7 @@ export const useAgentChatSession = ({
|
|||||||
async ({
|
async ({
|
||||||
prompt: rawPrompt,
|
prompt: rawPrompt,
|
||||||
sessionIdOverride,
|
sessionIdOverride,
|
||||||
|
regenerateFromMessageIndex,
|
||||||
preparedMessages,
|
preparedMessages,
|
||||||
userMessage,
|
userMessage,
|
||||||
assistantMessage,
|
assistantMessage,
|
||||||
@@ -644,6 +646,7 @@ export const useAgentChatSession = ({
|
|||||||
sessionId: sessionIdOverride ?? sessionIdRef.current,
|
sessionId: sessionIdOverride ?? sessionIdRef.current,
|
||||||
model: getModel?.(),
|
model: getModel?.(),
|
||||||
approvalMode: getApprovalMode?.(),
|
approvalMode: getApprovalMode?.(),
|
||||||
|
regenerateFromMessageIndex,
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
onEvent: (event) =>
|
onEvent: (event) =>
|
||||||
applyStreamEvent(event, {
|
applyStreamEvent(event, {
|
||||||
@@ -991,6 +994,7 @@ export const useAgentChatSession = ({
|
|||||||
setMessages(nextMessages);
|
setMessages(nextMessages);
|
||||||
await runPrompt({
|
await runPrompt({
|
||||||
prompt: lastUserContent,
|
prompt: lastUserContent,
|
||||||
|
regenerateFromMessageIndex: lastUserIndex,
|
||||||
preparedMessages: [
|
preparedMessages: [
|
||||||
...nextMessages,
|
...nextMessages,
|
||||||
nextUserMessage,
|
nextUserMessage,
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ describe("streamAgentChat", () => {
|
|||||||
session_id: undefined,
|
session_id: undefined,
|
||||||
model: "deepseek/deepseek-v4-pro",
|
model: "deepseek/deepseek-v4-pro",
|
||||||
approval_mode: undefined,
|
approval_mode: undefined,
|
||||||
|
regenerate_from_message_index: undefined,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ type StreamOptions = {
|
|||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
model?: AgentModel;
|
model?: AgentModel;
|
||||||
approvalMode?: AgentApprovalMode;
|
approvalMode?: AgentApprovalMode;
|
||||||
|
regenerateFromMessageIndex?: number;
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
onEvent: (event: StreamEvent) => void;
|
onEvent: (event: StreamEvent) => void;
|
||||||
};
|
};
|
||||||
@@ -286,6 +287,7 @@ export const streamAgentChat = async ({
|
|||||||
sessionId,
|
sessionId,
|
||||||
model,
|
model,
|
||||||
approvalMode,
|
approvalMode,
|
||||||
|
regenerateFromMessageIndex,
|
||||||
signal,
|
signal,
|
||||||
onEvent,
|
onEvent,
|
||||||
}: StreamOptions) => {
|
}: StreamOptions) => {
|
||||||
@@ -305,6 +307,7 @@ export const streamAgentChat = async ({
|
|||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
model,
|
model,
|
||||||
approval_mode: approvalMode,
|
approval_mode: approvalMode,
|
||||||
|
regenerate_from_message_index: regenerateFromMessageIndex,
|
||||||
}),
|
}),
|
||||||
projectHeaderMode: "include",
|
projectHeaderMode: "include",
|
||||||
userHeaderMode: "include",
|
userHeaderMode: "include",
|
||||||
|
|||||||
Reference in New Issue
Block a user