fix: 协助卡停轮与提交防 409,隐藏配置向导会话,并限制岗位会商产物重复写入

澄清中间件改为 ToolMessage + after_model 停轮,前端提交前取消残留 run;系统/向导 thread_type 从对话列表排除;岗位总结席位加 write_file 上限。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
董宏凯andCursor committed 2026-08-23 20:29:59 +08:00
1 parent 51afebb394
commit b81d200eca
31 files changed
+1459 -592

No files matched your search

+44 -13
View File
@@ -28,6 +28,7 @@ import {
isAbortLikeError,
isTransientStreamTransportError,
} from "./thread-access-error";
import { isHiddenFromRecentChats, shouldHideSystemThreadsFromList } from "./utils";
export type ToolEndEvent = {
name: string;
@@ -210,6 +211,39 @@ export async function stopThreadRun(
}
}
/**
* 协助卡提交前:若上一轮还在流式(弱模型出卡后偶发未停干净),先取消服务端 run
* 并断开本地 SSE,避免 409「已有活跃 run」或用户点了选项却发不出去。
*/
export async function stopActiveThreadBeforeClarificationReply(
threadId: string | null | undefined,
thread: { isLoading?: boolean; stop: () => void | Promise<void> },
): Promise<void> {
let storedRunId: string | null = null;
if (threadId && typeof window !== "undefined") {
try {
storedRunId = normalizeStoredRunId(
window.sessionStorage.getItem(`lg:stream:${threadId}`),
);
} catch {
storedRunId = null;
}
}
if (!thread.isLoading && !storedRunId) return;
try {
await stopThreadRun(threadId);
} catch {
/* best-effort */
}
try {
await Promise.resolve(thread.stop());
} catch {
/* best-effort */
}
// cancel 落地需要一拍,立刻 submit 仍可能 409。
await new Promise((resolve) => setTimeout(resolve, 120));
}
function getStreamErrorMessage(error: unknown): string {
if (typeof error === "string" && error.trim()) {
return error;
@@ -1451,18 +1485,10 @@ export function useThreads(
}
// Safety net on top of the backend's system-thread exclusion: drop
// machine-created threads (scheduled tasks, roundtable workers,
// notebooks) in case an older backend still returns them.
return threads.filter((t) => {
const metadata = t.metadata as Record<string, unknown> | null;
if (metadata?.system) return false;
const threadType = metadata?.thread_type;
return (
threadType !== "notebook" &&
threadType !== "scheduler" &&
threadType !== "roundtable"
);
});
// machine-created / wizard threads (scheduled tasks, report-structure
// setup, writing setup, notebooks, …) in case an older backend still
// returns them.
return threads.filter((t) => !isHiddenFromRecentChats(t));
},
refetchOnWindowFocus: false,
});
@@ -1545,8 +1571,13 @@ export function useThreadsPage(options: {
throw new Error("Failed to load conversations");
}
const rows = (await response.json()) as AgentThread[];
// 与后端 exclude_system 对齐:普通列表再兜一层。调用方显式按
// thread_type / system 取数(笔记本等)时不滤,避免把目标会话藏掉。
const visible = shouldHideSystemThreadsFromList(metadata)
? rows.filter((thread) => !isHiddenFromRecentChats(thread))
: rows;
return {
threads: rows.slice(0, pageSize),
threads: visible.slice(0, pageSize),
hasMore: rows.length > pageSize,
};
},