Merge branch 'ji' into master
This commit is contained in:
commit
3aa629f0df
5 files changed
+23
-9
No files matched your search
@@ -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(
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
* {@link DESENSITIZE_MAP}。
|
||||
*/
|
||||
export const SEED_DESENSITIZE_MAP: Readonly<Record<string, string>> = Object.freeze({
|
||||
// 任务工作区业务名 → 业务码(脱敏展示)。整词在前,优先于下面更短的「任务」「行动」匹配。
|
||||
任务分析: "rwfx",
|
||||
三情分析: "3qfx",
|
||||
行动分析: "xdfx",
|
||||
方案: "FA",
|
||||
设计: "SJ",
|
||||
任务: "RW",
|
||||
|
||||
@@ -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">
|
||||
|
||||
+4
-3
@@ -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}
|
||||
</>
|
||||
) : (
|
||||
|
||||
Reference in new issue
Block a user