Merge branch 'ji' into master

This commit is contained in:
吉鑫升 committed 2026-06-18 17:17:11 +08:00
commit 3aa629f0df
5 files changed
+23 -9

No files matched your search

+4 -1
View File
@@ -785,7 +785,10 @@ export function useThreadStream({
} as typeof thread)
: thread;
return [mergedThread, sendMessage, isUploading] as const;
// 第 4 个返回值 `onStreamThreadId` = 底层 useStream 当前实际绑定的线程 id(新建/未保存时为 null)。
// 调用方据此判断「流是否已切到全新线程」,避免在切换会话的那一帧把消息发进上一个会话
// (submit 的 threadId 选项仅在 hook 线程为 null/undefined 时才生效)。
return [mergedThread, sendMessage, isUploading, onStreamThreadId] as const;
}
export function useThreads(
+4
View File
@@ -11,6 +11,10 @@
* {@link DESENSITIZE_MAP}。
*/
export const SEED_DESENSITIZE_MAP: Readonly<Record<string, string>> = Object.freeze({
// 任务工作区业务名 → 业务码(脱敏展示)。整词在前,优先于下面更短的「任务」「行动」匹配。
任务分析: "rwfx",
三情分析: "3qfx",
行动分析: "xdfx",
方案: "FA",
设计: "SJ",
任务: "RW",
+8 -2
View File
@@ -130,7 +130,7 @@ export default function AgentChatPage({
}, [isNewThread, threadId, agent_id]);
const { showNotification } = useNotification();
const [thread, sendMessage] = useThreadStream({
const [thread, sendMessage, , streamThreadId] = useThreadStream({
threadId: isNewThread ? undefined : threadId,
assistantId: agent_id,
context: { ...settings.context, agent_id },
@@ -229,13 +229,19 @@ export default function AgentChatPage({
// 纯绑定任务深链(3qfx/xdfx,无闸门):进入新建对话即自动发出任务开场信息。
// 每次新建对话都带(与 rwfx 闸门「开始问答」发出等价);ref 防止同一会话内重复发出。
//
// 必须等 `streamThreadId == null`(底层 stream 已切到全新线程)才发:从已有会话点「新建对话」时,
// `isNewThread` 先翻 true,但 useThreadStream 的 onStreamThreadId 要慢一帧才重置为 null。
// 若在那一帧就 submit,hook 仍绑定上一个会话,submit 的 threadId 选项被忽略 → 开场信息发进
// 上一个对话(表现为「一直在同一个聊天框里发消息」)。等它归零再发即落到新建线程。
useEffect(() => {
if (!taskAutoSendText) return;
if (!isNewThread) return;
if (streamThreadId != null) return;
if (taskAutoSentRef.current) return;
taskAutoSentRef.current = true;
handleSubmit({ text: taskAutoSendText, files: [] });
}, [taskAutoSendText, isNewThread, handleSubmit]);
}, [taskAutoSendText, isNewThread, streamThreadId, handleSubmit]);
const handleClarificationSubmit = useCallback(
(answer: string) => {
@@ -148,9 +148,9 @@ function TaskJumpBar({ business, taskId }: { business: TaskBusiness; taskId: str
key={btn.id}
className="h-11 gap-2 border-transparent bg-[var(--color-main)] px-6 text-base text-white shadow-sm hover:bg-[var(--brand-950)]"
onClick={() => handleRun(btn)}
title={btn.label}
title={desensitize(btn.label)}
>
<span className="truncate">{btn.label}</span>
<span className="truncate">{desensitize(btn.label)}</span>
{btn.linkType === "url" ? (
<ExternalLink className="h-5 w-5 shrink-0" />
) : btn.linkType === "purpose" ? (
@@ -191,7 +191,7 @@ function TaskConversationsList({
const navigate = useNavigate();
const { threads, isLoading } = useTaskThreads(taskId, agentId);
const currentThreadId = useMemo(() => parseThreadId(pathname, chatsBase), [pathname, chatsBase]);
const businessName = TASK_BUSINESSES.find((b) => b.code === business)?.name ?? "";
const businessName = desensitize(TASK_BUSINESSES.find((b) => b.code === business)?.name ?? "");
return (
<div className="bg-background/85 border-border/70 flex w-64 shrink-0 flex-col border-r shadow-[12px_0_30px_-30px_rgba(15,23,42,0.45)] backdrop-blur-xl dark:border-[#1b477e]/70 dark:bg-[#061b35]/82">
@@ -31,6 +31,7 @@ import {
type TaskPurposeResult,
} from "@/core/auth/task-purpose";
import { fetchTaskIdFromAction } from "@/core/auth/task-deeplink";
import { desensitize } from "@/lib/desensitize";
import { cn } from "@/lib/utils";
/** 目的树表格:拍平成行,列数随数据自适应;层级缺失补空、字段变动不崩。 */
@@ -58,7 +59,7 @@ export function PurposeTable({ tree, className }: { tree: PurposeTreeNode[]; cla
key={i}
className="bg-muted/60 border-border/60 sticky top-0 border px-3 py-1.5 text-left font-medium whitespace-nowrap"
>
{h}
{desensitize(h)}
</th>
))}
</tr>
@@ -72,9 +73,9 @@ export function PurposeTable({ tree, className }: { tree: PurposeTreeNode[]; cla
<td key={ci} className="border-border/60 border px-3 py-1.5">
{cell ? (
<>
<span>{cell.text || "(空)"}</span>
<span>{cell.text ? desensitize(cell.text) : "(空)"}</span>
{cell.reason ? (
<span className="text-muted-foreground block text-xs">理由:{cell.reason}</span>
<span className="text-muted-foreground block text-xs">理由:{desensitize(cell.reason)}</span>
) : null}
</>
) : (