fix: 协助卡停轮与提交防 409,隐藏配置向导会话,并限制岗位会商产物重复写入
澄清中间件改为 ToolMessage + after_model 停轮,前端提交前取消残留 run;系统/向导 thread_type 从对话列表排除;岗位总结席位加 write_file 上限。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
51afebb394
commit
b81d200eca
31 files changed
+1459
-592
No files matched your search
@@ -31,7 +31,7 @@ import { queueLlmWikiConversationDeposit } from "@/core/llmwiki/conversation-dep
|
||||
import { useModels } from "@/core/models/hooks";
|
||||
import { useNotification } from "@/core/notification/hooks";
|
||||
import { saveLastAgentId, useThreadSettings } from "@/core/settings";
|
||||
import { stopThreadRun, useThreadStream } from "@/core/threads/hooks";
|
||||
import { stopActiveThreadBeforeClarificationReply, stopThreadRun, useThreadStream } from "@/core/threads/hooks";
|
||||
import { textOfMessage } from "@/core/threads/utils";
|
||||
import { OptType, writeYLog } from "@/core/log/y-log";
|
||||
import {
|
||||
@@ -542,11 +542,12 @@ export default function AgentChatPage({
|
||||
}, [taskAutoStart, taskStartText, isNewThread, handleSubmit]);
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
(answer: string) => {
|
||||
async (answer: string) => {
|
||||
setHasStartedConversation(true);
|
||||
void sendMessage(threadId, { text: answer, files: [] }, { agent_id });
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, thread);
|
||||
await sendMessage(threadId, { text: answer, files: [] }, { agent_id });
|
||||
},
|
||||
[sendMessage, threadId, agent_id],
|
||||
[sendMessage, thread, threadId, agent_id],
|
||||
);
|
||||
|
||||
const handleStop = useCallback(async () => {
|
||||
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
useKnowledgeRagEnabled,
|
||||
useThreadSettings,
|
||||
} from "@/core/settings";
|
||||
import { useThreadStream } from "@/core/threads/hooks";
|
||||
import { useThreadStream, stopActiveThreadBeforeClarificationReply } from "@/core/threads/hooks";
|
||||
import { queueLlmWikiConversationDeposit } from "@/core/llmwiki/conversation-deposit";
|
||||
import { useSingleRoundRagMessages } from "@/core/threads/use-single-round-rag";
|
||||
import { useMultiRoundRagMessages } from "@/core/threads/use-multi-round-rag";
|
||||
@@ -525,11 +525,12 @@ export default function ChatPage() {
|
||||
);
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
(answer: string) => {
|
||||
async (answer: string) => {
|
||||
setHasStartedConversation(true);
|
||||
void sendMessage(threadId, { text: answer, files: [] });
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, thread);
|
||||
await sendMessage(threadId, { text: answer, files: [] });
|
||||
},
|
||||
[sendMessage, threadId],
|
||||
[sendMessage, thread, threadId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { setStoredAuth } from "@/core/auth";
|
||||
import { resolveEmbedChatParams } from "@/core/embed/params";
|
||||
import { registerEmbedSession } from "@/core/embed/status-api";
|
||||
import { useThreadSettings } from "@/core/settings";
|
||||
import { useThreadStream } from "@/core/threads/hooks";
|
||||
import { stopActiveThreadBeforeClarificationReply, useThreadStream } from "@/core/threads/hooks";
|
||||
import { uuid } from "@/core/utils/uuid";
|
||||
import { ChatBox } from "@/components/workspace/chats";
|
||||
import {
|
||||
@@ -110,10 +110,11 @@ export default function EmbedChatPage() {
|
||||
}, [authReady, threadId, registerSessionForThread]);
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
(answer: string) => {
|
||||
void sendMessage(threadId, { text: answer, files: [] });
|
||||
async (answer: string) => {
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, thread);
|
||||
await sendMessage(threadId, { text: answer, files: [] });
|
||||
},
|
||||
[sendMessage, threadId],
|
||||
[sendMessage, thread, threadId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
useThreadSettings,
|
||||
} from "@/core/settings";
|
||||
import { usePluginManagementSettings } from "@/core/system-settings/hooks";
|
||||
import { useThreadStream } from "@/core/threads/hooks";
|
||||
import { stopActiveThreadBeforeClarificationReply, useThreadStream } from "@/core/threads/hooks";
|
||||
import { textOfMessage } from "@/core/threads/utils";
|
||||
import { env } from "@/env";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -336,11 +336,12 @@ export default function IframeChatPage() {
|
||||
);
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
(answer: string) => {
|
||||
async (answer: string) => {
|
||||
setHasStartedConversation(true);
|
||||
void sendMessage(threadId, { text: answer, files: [] });
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, thread);
|
||||
await sendMessage(threadId, { text: answer, files: [] });
|
||||
},
|
||||
[sendMessage, threadId],
|
||||
[sendMessage, thread, threadId],
|
||||
);
|
||||
|
||||
const handleAgentChange = useCallback((agentId: string | null) => {
|
||||
|
||||
@@ -53,7 +53,7 @@ import { useI18n } from "@/core/i18n/hooks";
|
||||
import { useModels } from "@/core/models/hooks";
|
||||
import { isAgentSkillCandidate } from "@/core/skills";
|
||||
import { useSkills } from "@/core/skills/hooks";
|
||||
import { useThreadStream } from "@/core/threads/hooks";
|
||||
import { stopActiveThreadBeforeClarificationReply, useThreadStream } from "@/core/threads/hooks";
|
||||
import { uuid } from "@/core/utils/uuid";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -335,13 +335,25 @@ export default function NewAgentPage() {
|
||||
// Chat is purely a discussion channel. The agent record is only
|
||||
// created when the user explicitly clicks Save (top-right). If the
|
||||
// model proposes a config via setup_agent, our approval handler
|
||||
// prefills the form locally 鈥?it does NOT persist anything.
|
||||
// prefills the form locally — it does NOT persist anything.
|
||||
await ensureThreadExists();
|
||||
await sendMessage(threadId, { text: trimmed, files: [] });
|
||||
},
|
||||
[ensureThreadExists, sendMessage, thread.isLoading, threadId],
|
||||
);
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
async (text: string) => {
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return;
|
||||
// 协助卡提交不能因 isLoading 直接丢弃——弱模型出卡后可能仍在流式。
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, thread);
|
||||
await ensureThreadExists();
|
||||
await sendMessage(threadId, { text: trimmed, files: [] });
|
||||
},
|
||||
[ensureThreadExists, sendMessage, thread, threadId],
|
||||
);
|
||||
|
||||
const handleApproveSetupAgent = useCallback(
|
||||
async (payload: SetupAgentApprovalPayload) => {
|
||||
// Approving the model's setup_agent proposal **does not** persist
|
||||
@@ -425,7 +437,7 @@ export default function NewAgentPage() {
|
||||
className="size-full"
|
||||
threadId={threadId}
|
||||
thread={thread}
|
||||
onClarificationSubmit={handleChatSubmit}
|
||||
onClarificationSubmit={handleClarificationSubmit}
|
||||
onSetupAgentApprove={handleApproveSetupAgent}
|
||||
onSetupAgentReject={handleRejectSetupAgent}
|
||||
/>
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { useNotebookChat, useNotebookSources, useNotebookThreads, useStudioNotebooks } from "@/core/studio/hooks";
|
||||
import { stopActiveThreadBeforeClarificationReply } from "@/core/threads/hooks";
|
||||
import { fetchDocumentByChunk } from "@/core/studio/api";
|
||||
import type { DocumentWithChunks } from "@/core/studio/api";
|
||||
import type { SourceItem } from "@/core/studio/types";
|
||||
@@ -381,12 +382,13 @@ export default function StudioNotebookDetailPage({
|
||||
// Clarification 卡片的「发送」按钮回调。MessageList 内部把用户选中的选项 +
|
||||
// 自由文本合并成一段 answer 传过来,这里走和普通发送同一条 send() 链路,
|
||||
// 把当前选中的来源也一并带上,保持上下文一致。
|
||||
// 弱模型出卡后可能仍在流式:先 stop 再发,不能因 isStreaming 直接丢弃。
|
||||
const handleClarificationSubmit = useCallback(
|
||||
async (answer: string) => {
|
||||
if (isStreaming) return;
|
||||
await send(answer, selectedSourceIds);
|
||||
await stopActiveThreadBeforeClarificationReply(chatThreadId, thread);
|
||||
await send(answer, selectedSourceIds, { fromClarification: true });
|
||||
},
|
||||
[send, selectedSourceIds, isStreaming],
|
||||
[send, selectedSourceIds, chatThreadId, thread],
|
||||
);
|
||||
|
||||
const handleBackToList = () => {
|
||||
|
||||
@@ -87,7 +87,11 @@ import { useLocalSettings } from "@/core/settings/hooks";
|
||||
import { useModels } from "@/core/models/hooks";
|
||||
import type { DocumentRewriteStreamEvent, DocumentRewriteSummary } from "@/open-canvas/api/rewrite";
|
||||
import { useDocumentRewrite } from "@/open-canvas/hooks/useDocumentRewrite";
|
||||
import { stopThreadRun, useThreadStream } from "@/core/threads/hooks";
|
||||
import {
|
||||
stopActiveThreadBeforeClarificationReply,
|
||||
stopThreadRun,
|
||||
useThreadStream,
|
||||
} from "@/core/threads/hooks";
|
||||
import {
|
||||
extractContentFromMessage,
|
||||
extractReasoningContentFromMessage,
|
||||
@@ -947,9 +951,11 @@ function DeepResearchWorkbenchInner() {
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
async (text: string) => {
|
||||
const threadId = session?.runtimeThreadId;
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, collectorThread);
|
||||
await sendCollectorMessage(text);
|
||||
},
|
||||
[sendCollectorMessage],
|
||||
[collectorThread, sendCollectorMessage, session?.runtimeThreadId],
|
||||
);
|
||||
|
||||
// The very first research topic: auto-sent into the freshly pre-built
|
||||
|
||||
@@ -28,7 +28,7 @@ import { extractContentFromMessage, extractReasoningContentFromMessage, hasToolC
|
||||
import { getAPIClient } from "@/core/api";
|
||||
import { useModels } from "@/core/models/hooks";
|
||||
import { useSkills } from "@/core/skills/hooks";
|
||||
import { useThreadStream } from "@/core/threads/hooks";
|
||||
import { stopActiveThreadBeforeClarificationReply, useThreadStream } from "@/core/threads/hooks";
|
||||
import { uuid } from "@/core/utils/uuid";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -79,7 +79,10 @@ export function ReportStructureSetupChat({
|
||||
|
||||
const ensureThreadExists = useCallback(async () => {
|
||||
if (threadPrepared) return;
|
||||
await getAPIClient().threads.create({ threadId, metadata: { thread_type: "report_structure_setup" } });
|
||||
await getAPIClient().threads.create({
|
||||
threadId,
|
||||
metadata: { thread_type: "report_structure_setup", system: true },
|
||||
});
|
||||
setThreadPrepared(true);
|
||||
}, [threadId, threadPrepared]);
|
||||
|
||||
@@ -99,15 +102,9 @@ export function ReportStructureSetupChat({
|
||||
|
||||
const handleClarificationSubmit = useCallback(
|
||||
async (text: string) => {
|
||||
if (thread.isLoading) {
|
||||
try {
|
||||
await Promise.resolve(thread.stop());
|
||||
} catch {
|
||||
/* best-effort: still send the answer */
|
||||
}
|
||||
}
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return;
|
||||
await stopActiveThreadBeforeClarificationReply(threadId, thread);
|
||||
await ensureThreadExists();
|
||||
await sendMessage(threadId, { text: trimmed, files: [] });
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user