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)
|
} as typeof thread)
|
||||||
: 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(
|
export function useThreads(
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
* {@link DESENSITIZE_MAP}。
|
* {@link DESENSITIZE_MAP}。
|
||||||
*/
|
*/
|
||||||
export const SEED_DESENSITIZE_MAP: Readonly<Record<string, string>> = Object.freeze({
|
export const SEED_DESENSITIZE_MAP: Readonly<Record<string, string>> = Object.freeze({
|
||||||
|
// 任务工作区业务名 → 业务码(脱敏展示)。整词在前,优先于下面更短的「任务」「行动」匹配。
|
||||||
|
任务分析: "rwfx",
|
||||||
|
三情分析: "3qfx",
|
||||||
|
行动分析: "xdfx",
|
||||||
方案: "FA",
|
方案: "FA",
|
||||||
设计: "SJ",
|
设计: "SJ",
|
||||||
任务: "RW",
|
任务: "RW",
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export default function AgentChatPage({
|
|||||||
}, [isNewThread, threadId, agent_id]);
|
}, [isNewThread, threadId, agent_id]);
|
||||||
|
|
||||||
const { showNotification } = useNotification();
|
const { showNotification } = useNotification();
|
||||||
const [thread, sendMessage] = useThreadStream({
|
const [thread, sendMessage, , streamThreadId] = useThreadStream({
|
||||||
threadId: isNewThread ? undefined : threadId,
|
threadId: isNewThread ? undefined : threadId,
|
||||||
assistantId: agent_id,
|
assistantId: agent_id,
|
||||||
context: { ...settings.context, agent_id },
|
context: { ...settings.context, agent_id },
|
||||||
@@ -229,13 +229,19 @@ export default function AgentChatPage({
|
|||||||
|
|
||||||
// 纯绑定任务深链(3qfx/xdfx,无闸门):进入新建对话即自动发出任务开场信息。
|
// 纯绑定任务深链(3qfx/xdfx,无闸门):进入新建对话即自动发出任务开场信息。
|
||||||
// 每次新建对话都带(与 rwfx 闸门「开始问答」发出等价);ref 防止同一会话内重复发出。
|
// 每次新建对话都带(与 rwfx 闸门「开始问答」发出等价);ref 防止同一会话内重复发出。
|
||||||
|
//
|
||||||
|
// 必须等 `streamThreadId == null`(底层 stream 已切到全新线程)才发:从已有会话点「新建对话」时,
|
||||||
|
// `isNewThread` 先翻 true,但 useThreadStream 的 onStreamThreadId 要慢一帧才重置为 null。
|
||||||
|
// 若在那一帧就 submit,hook 仍绑定上一个会话,submit 的 threadId 选项被忽略 → 开场信息发进
|
||||||
|
// 上一个对话(表现为「一直在同一个聊天框里发消息」)。等它归零再发即落到新建线程。
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!taskAutoSendText) return;
|
if (!taskAutoSendText) return;
|
||||||
if (!isNewThread) return;
|
if (!isNewThread) return;
|
||||||
|
if (streamThreadId != null) return;
|
||||||
if (taskAutoSentRef.current) return;
|
if (taskAutoSentRef.current) return;
|
||||||
taskAutoSentRef.current = true;
|
taskAutoSentRef.current = true;
|
||||||
handleSubmit({ text: taskAutoSendText, files: [] });
|
handleSubmit({ text: taskAutoSendText, files: [] });
|
||||||
}, [taskAutoSendText, isNewThread, handleSubmit]);
|
}, [taskAutoSendText, isNewThread, streamThreadId, handleSubmit]);
|
||||||
|
|
||||||
const handleClarificationSubmit = useCallback(
|
const handleClarificationSubmit = useCallback(
|
||||||
(answer: string) => {
|
(answer: string) => {
|
||||||
|
|||||||
@@ -148,9 +148,9 @@ function TaskJumpBar({ business, taskId }: { business: TaskBusiness; taskId: str
|
|||||||
key={btn.id}
|
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)]"
|
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)}
|
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" ? (
|
{btn.linkType === "url" ? (
|
||||||
<ExternalLink className="h-5 w-5 shrink-0" />
|
<ExternalLink className="h-5 w-5 shrink-0" />
|
||||||
) : btn.linkType === "purpose" ? (
|
) : btn.linkType === "purpose" ? (
|
||||||
@@ -191,7 +191,7 @@ function TaskConversationsList({
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { threads, isLoading } = useTaskThreads(taskId, agentId);
|
const { threads, isLoading } = useTaskThreads(taskId, agentId);
|
||||||
const currentThreadId = useMemo(() => parseThreadId(pathname, chatsBase), [pathname, chatsBase]);
|
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 (
|
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">
|
<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,
|
type TaskPurposeResult,
|
||||||
} from "@/core/auth/task-purpose";
|
} from "@/core/auth/task-purpose";
|
||||||
import { fetchTaskIdFromAction } from "@/core/auth/task-deeplink";
|
import { fetchTaskIdFromAction } from "@/core/auth/task-deeplink";
|
||||||
|
import { desensitize } from "@/lib/desensitize";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
/** 目的树表格:拍平成行,列数随数据自适应;层级缺失补空、字段变动不崩。 */
|
/** 目的树表格:拍平成行,列数随数据自适应;层级缺失补空、字段变动不崩。 */
|
||||||
@@ -58,7 +59,7 @@ export function PurposeTable({ tree, className }: { tree: PurposeTreeNode[]; cla
|
|||||||
key={i}
|
key={i}
|
||||||
className="bg-muted/60 border-border/60 sticky top-0 border px-3 py-1.5 text-left font-medium whitespace-nowrap"
|
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>
|
</th>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</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">
|
<td key={ci} className="border-border/60 border px-3 py-1.5">
|
||||||
{cell ? (
|
{cell ? (
|
||||||
<>
|
<>
|
||||||
<span>{cell.text || "(空)"}</span>
|
<span>{cell.text ? desensitize(cell.text) : "(空)"}</span>
|
||||||
{cell.reason ? (
|
{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}
|
) : null}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in new issue
Block a user