fix: unify chat process and reply presentation
This commit is contained in:
@@ -10,11 +10,14 @@ import { showMapNotice } from "@/features/map/core";
|
||||
import { findOwnedWorkbenchProject } from "../api/project-client";
|
||||
import type { InvestigationDiscussion } from "../api/investigation-report";
|
||||
import {
|
||||
useInteractionRequests,
|
||||
useAgentConnection,
|
||||
FrontendActionExecutor,
|
||||
agentTaskDiscussionContextSchema,
|
||||
type AgentTaskDiscussionContext,
|
||||
agentBootstrapKey,
|
||||
createAgentApiClient,
|
||||
AgentResponseFinishedError,
|
||||
useAgentMessageInbox,
|
||||
fetchAgentBootstrap,
|
||||
resolveAgentModelSelection,
|
||||
@@ -59,6 +62,7 @@ import { useWorkbenchSessionResources } from "./workbench-session-resources";
|
||||
import { useAgentTopics } from "./use-agent-topics";
|
||||
import { useAgentHistory } from "./use-agent-history";
|
||||
import { agentRuntimes, createAgentRuntime, mergeHistoryMessages, resumeAgentRuntime, runtimeNeedsInput, runtimeRunning,
|
||||
isPendingInteractionError,
|
||||
type AgentReadingPosition, type AgentSessionRuntime } from "./agent-session-runtime";
|
||||
|
||||
const AGENT_PANEL_COLLAPSE_MS = 180;
|
||||
@@ -98,6 +102,7 @@ export function useWorkbenchAgent({
|
||||
clientRef.current = scopeClient;
|
||||
const projectScopeKey = `project:${getWorkbenchProject(getAccessToken)?.project_id ?? "default"}`;
|
||||
const scopeKey = projectScopeKey;
|
||||
const { connectionStatus, recheck: checkAgentConnection, recoveryVersion } = useAgentConnection(scopeClient, scopeKey);
|
||||
const history = useAgentHistory(scopeClient, scopeKey);
|
||||
const topics = useAgentTopics(scopeClient, scopeKey);
|
||||
const runtimeSummaries: AgentChatSessionSummary[] = agentRuntimes(resources).filter((entry) => entry.scope === scopeKey && entry.sessionId && entry.purpose !== "task_execution")
|
||||
@@ -142,8 +147,6 @@ export function useWorkbenchAgent({
|
||||
const [registry, setRegistry] = useState<UIRegistry | null>(null);
|
||||
const [sessionTitle, setSessionTitle] = useState("新对话");
|
||||
const [statusLabel, setStatusLabel] = useState("Agent 后端连接中");
|
||||
const [connectionStatus, setConnectionStatus] =
|
||||
useState<AgentConnectionStatus>("connecting");
|
||||
const [modelOptions, setModelOptions] = useState<AgentModelOption[]>([]);
|
||||
const [selectedModel, setSelectedModel] = useState("");
|
||||
const [inputDelivery, setInputDelivery] = useState<AgentInputDelivery>("steer");
|
||||
@@ -162,6 +165,44 @@ export function useWorkbenchAgent({
|
||||
const [questionOverrides, setQuestionOverrides] = useState<Record<string, QuestionOverride>>({});
|
||||
const agentMessageInbox = useAgentMessageInbox(clientRef.current, sessionPurpose === "ordinary_chat" ? sessionId : null);
|
||||
const refreshAgentMessageInbox = agentMessageInbox.refresh;
|
||||
const continueInteraction = useCallback(async (owningSessionId: string, interactionId: string) => {
|
||||
const target = agentRuntimes(resources).find((entry) => entry.scope === scopeKey && entry.sessionId === owningSessionId);
|
||||
if (!target || target.client !== scopeClient || resources.disposed) throw new Error("原会话已关闭,请重新打开后继续。");
|
||||
const record = await target.client.getInteractionRequest(owningSessionId, interactionId);
|
||||
if (target.client !== scopeClient || resources.disposed || !agentRuntimes(resources).includes(target)) return;
|
||||
if (!record.delivery || ["delivered", "cancelled"].includes(record.delivery.status)) return;
|
||||
const text = record.status === "skipped" ? "已跳过本组提问。" : record.questions.map((question) => {
|
||||
const answer = record.answers?.find((item) => item.question_id === question.question_id);
|
||||
return `${question.title}:${[...(answer?.selected_options.map((option) => option.label) ?? []), answer?.custom_text].filter(Boolean).join(";")}`;
|
||||
}).join("\n");
|
||||
const alreadyPresent = target.chat.messages.some((message) => message.id === record.delivery!.native_message_id);
|
||||
const replyMessage: AgentUiMessage = { id: record.delivery.native_message_id, role: "user", parts: [
|
||||
{ type: "text", text }, { type: "data-interaction_reply", data: record },
|
||||
] };
|
||||
if (alreadyPresent) target.chat.messages = target.chat.messages.map((message) => message.id === replyMessage.id ? replyMessage : message);
|
||||
target.runStatus = "running";
|
||||
try {
|
||||
await target.chat.sendMessage(alreadyPresent ? undefined : replyMessage, { body: {
|
||||
session_id: owningSessionId, interaction_id: interactionId, model: selectedModel || undefined,
|
||||
capabilities: frontendActionEnabledRef.current ? ["host-question@1", "frontend-action@1"] : ["host-question@1"],
|
||||
approval_mode: approvalMode, task_context: target.taskDiscussion?.context,
|
||||
} });
|
||||
} catch (error) { target.runStatus = "error"; throw error; }
|
||||
finally {
|
||||
if (!resources.disposed && target.client === scopeClient && !runtimeRunning(target)) {
|
||||
try {
|
||||
const loaded = await target.client.loadSession(owningSessionId, { messageLimit: 40 });
|
||||
if (loaded && !resources.disposed && target.client === scopeClient) {
|
||||
target.chat.messages = mergeHistoryMessages(target.chat.messages, toAgentUiMessages(loaded.messages));
|
||||
resources.notify();
|
||||
}
|
||||
} catch { /* A failed reconciliation leaves the accepted answer intact. */ }
|
||||
}
|
||||
}
|
||||
}, [resources, scopeKey, scopeClient, selectedModel, approvalMode]);
|
||||
const interactionRequests = useInteractionRequests(scopeClient, scopeKey, sessionId, continueInteraction);
|
||||
const refreshInteractionRequests = interactionRequests.refresh;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
sessionIdRef.current = sessionId;
|
||||
@@ -232,7 +273,6 @@ export function useWorkbenchAgent({
|
||||
|
||||
const handleDataPart = useCallback(
|
||||
(part: AgentDataPart) => {
|
||||
setConnectionStatus("online");
|
||||
const eventSessionId = getDataString(part.data, "session_id");
|
||||
if (eventSessionId && sessionIdRef.current && eventSessionId !== sessionIdRef.current) {
|
||||
return;
|
||||
@@ -247,6 +287,7 @@ export function useWorkbenchAgent({
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (part.type === "data-interaction_request") { void refreshInteractionRequests(); return; }
|
||||
if (part.type === "data-agent_message") { refreshAgentMessageInbox(); return; }
|
||||
if (part.type === "data-user_input" && part.data.status === "delivered") {
|
||||
chatRef.current.setMessages((current) => applySessionStreamEvent(current, { type: "user_input", data: part.data }));
|
||||
@@ -295,7 +336,7 @@ export function useWorkbenchAgent({
|
||||
});
|
||||
});
|
||||
},
|
||||
[refreshAgentMessageInbox, applySessionId, claimEnvelope, handleCredentialRefresh, handleFrontendAction, onUiEnvelope]
|
||||
[refreshInteractionRequests, refreshAgentMessageInbox, applySessionId, claimEnvelope, handleCredentialRefresh, handleFrontendAction, onUiEnvelope]
|
||||
);
|
||||
|
||||
const transport = useMemo(() => createWorkbenchAgentTransport(scopeClient, getAccessToken,
|
||||
@@ -355,9 +396,14 @@ export function useWorkbenchAgent({
|
||||
|
||||
const {
|
||||
data: backendConnection,
|
||||
error: backendConnectionError
|
||||
error: backendConnectionError,
|
||||
mutate: refreshBootstrap
|
||||
} = useSWR([...agentBootstrapKey, getAccessToken, scopeKey], () => fetchAgentBootstrap(scopeClient), {
|
||||
shouldRetryOnError: false
|
||||
shouldRetryOnError: true,
|
||||
errorRetryInterval: 5_000,
|
||||
errorRetryCount: 3,
|
||||
revalidateOnFocus: true,
|
||||
revalidateOnReconnect: true
|
||||
});
|
||||
const clearCollapseTimer = useCallback(() => {
|
||||
if (collapseTimerRef.current !== null) {
|
||||
@@ -374,6 +420,7 @@ export function useWorkbenchAgent({
|
||||
}, []);
|
||||
|
||||
const stopSessionStreamSubscription = useCallback(() => {
|
||||
clearTimeout(runtimeRef.current?.recoveryTimer);
|
||||
runtimeRef.current?.controller?.abort();
|
||||
if (runtimeRef.current) { runtimeRef.current.controller = undefined; runtimeRef.current.resumed = false; }
|
||||
}, []);
|
||||
@@ -402,8 +449,7 @@ export function useWorkbenchAgent({
|
||||
setRegistry(backendConnection.registry);
|
||||
setModelOptions(backendConnection.models);
|
||||
setSelectedModel((current) => resolveAgentModelSelection(backendConnection, current));
|
||||
if (chatRef.current.status === "ready") {
|
||||
setConnectionStatus("online");
|
||||
if (chatRef.current.status === "ready" && runtimeRef.current && !runtimeRunning(runtimeRef.current) && !runtimeRef.current.error) {
|
||||
setStatusLabel("准备就绪");
|
||||
}
|
||||
}, [backendConnection]);
|
||||
@@ -413,8 +459,7 @@ export function useWorkbenchAgent({
|
||||
return;
|
||||
}
|
||||
|
||||
setConnectionStatus("offline");
|
||||
setStatusLabel("Agent 后端不可用");
|
||||
if (runtimeRef.current && !runtimeRunning(runtimeRef.current) && !runtimeRef.current.error) setStatusLabel("Agent 初始化信息暂不可用");
|
||||
}, [backendConnectionError]);
|
||||
|
||||
const collapsePanel = useCallback(() => {
|
||||
@@ -469,6 +514,12 @@ export function useWorkbenchAgent({
|
||||
() => clientRef.current.listResponseInputs(sessionId!),
|
||||
{ refreshInterval: streaming ? 1000 : 0, shouldRetryOnError: false }
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!recoveryVersion) return;
|
||||
void refreshBootstrap();
|
||||
void refreshInteractionRequests();
|
||||
void refreshPendingInputs();
|
||||
}, [recoveryVersion, refreshBootstrap, refreshInteractionRequests, refreshPendingInputs]);
|
||||
const updateInputDelivery = useCallback(async (id: string, delivery: AgentInputDelivery) => {
|
||||
if (!sessionIdRef.current) return;
|
||||
try {
|
||||
@@ -504,10 +555,38 @@ export function useWorkbenchAgent({
|
||||
if (sessionIdRef.current === activeSessionId) void refreshPendingInputs().catch(() => {});
|
||||
}
|
||||
}, [refreshPendingInputs, resources, setPromptDraft]);
|
||||
const checkedLegacyQuestions = useRef(new Set<string>());
|
||||
const checkingLegacyQuestions = useRef(new Set<string>());
|
||||
const legacyQuestionScope = useRef(`${scopeKey}:${sessionId}`);
|
||||
if (legacyQuestionScope.current !== `${scopeKey}:${sessionId}`) {
|
||||
legacyQuestionScope.current = `${scopeKey}:${sessionId}`;
|
||||
checkedLegacyQuestions.current.clear();
|
||||
checkingLegacyQuestions.current.clear();
|
||||
}
|
||||
const messages = useMemo(
|
||||
() => toAgentChatMessages(chat.messages, permissionOverrides, questionOverrides),
|
||||
[chat.messages, permissionOverrides, questionOverrides]
|
||||
() => toAgentChatMessages(chat.messages, permissionOverrides, questionOverrides).map((message) => ({ ...message,
|
||||
questions: message.questions?.map((question) => question.status === "pending" && !checkedLegacyQuestions.current.has(`${scopeKey}:${question.sessionId}:${question.requestId}`)
|
||||
? { ...question, status: "checking" as const } : question),
|
||||
})),
|
||||
[chat.messages, permissionOverrides, questionOverrides, scopeKey]
|
||||
);
|
||||
useEffect(() => {
|
||||
const target = runtime;
|
||||
for (const message of messages) for (const question of message.questions ?? []) {
|
||||
const identity = `${scopeKey}:${question.sessionId}:${question.requestId}`;
|
||||
if (question.status !== "checking" || checkingLegacyQuestions.current.has(identity)) continue;
|
||||
checkingLegacyQuestions.current.add(identity);
|
||||
void target.client.getQuestionStatus(question.sessionId, question.requestId).then(({ status }) => {
|
||||
checkedLegacyQuestions.current.add(identity);
|
||||
checkingLegacyQuestions.current.delete(identity);
|
||||
target.questionOverrides = { ...target.questionOverrides, [question.requestId]: { status } };
|
||||
if (resources.activeAgent === target) setQuestionOverrides(target.questionOverrides);
|
||||
}).catch(() => {
|
||||
// Uncertainty keeps historical controls disabled until the session is reopened.
|
||||
checkingLegacyQuestions.current.delete(identity);
|
||||
});
|
||||
}
|
||||
}, [messages, resources, runtime, scopeKey]);
|
||||
const personaState = useMemo(
|
||||
() => deriveAgentPersonaState(messages, {
|
||||
chatStatus: chat.status,
|
||||
@@ -521,13 +600,15 @@ export function useWorkbenchAgent({
|
||||
|
||||
const handleSessionStreamEvent = useCallback(
|
||||
(event: AgentSessionStreamEvent, expectedSessionId: string) => {
|
||||
if (event.type === "interaction_request") { void refreshInteractionRequests(); return; }
|
||||
if (event.type === "state") {
|
||||
void refreshInteractionRequests();
|
||||
if (sessionIdRef.current !== expectedSessionId && sessionIdRef.current !== event.sessionId) {
|
||||
return;
|
||||
}
|
||||
const nextMessages = runtimeRef.current?.chat.messages ?? toAgentUiMessages(event.messages);
|
||||
setStreamRenderState(createCompletedStreamRenderState(nextMessages));
|
||||
setStatusLabel(event.isStreaming ? "Agent 会话流已恢复" : "Agent 历史会话已打开");
|
||||
setStatusLabel(event.runStatus === "waiting_input" ? "等待补充信息" : event.isStreaming ? "Agent 会话流已恢复" : "Agent 历史会话已打开");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -576,8 +657,9 @@ export function useWorkbenchAgent({
|
||||
setStatusLabel(title);
|
||||
}
|
||||
} else if (event.type === "done") {
|
||||
void refreshInteractionRequests();
|
||||
markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
|
||||
setStatusLabel("Agent 分析完成");
|
||||
setStatusLabel(event.data.reason === "waiting_input" ? "等待补充信息" : "Agent 分析完成");
|
||||
runtimeRef.current!.loadedAt = Date.now();
|
||||
} else if (event.type === "error") {
|
||||
markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
|
||||
@@ -587,7 +669,7 @@ export function useWorkbenchAgent({
|
||||
|
||||
// Message changes are applied once by the owning runtime, including background streams.
|
||||
},
|
||||
[refreshAgentMessageInbox, claimEnvelope, handleCredentialRefresh, handleFrontendAction, onUiEnvelope]
|
||||
[refreshInteractionRequests, refreshAgentMessageInbox, claimEnvelope, handleCredentialRefresh, handleFrontendAction, onUiEnvelope]
|
||||
);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@@ -595,23 +677,35 @@ export function useWorkbenchAgent({
|
||||
onData: handleDataPart,
|
||||
onEvent: (event) => handleSessionStreamEvent(event, runtime.sessionId ?? ""),
|
||||
onError: (error) => {
|
||||
void refreshInteractionRequests();
|
||||
markLastAssistantStreamDone(runtime.chat.messages, setStreamRenderState);
|
||||
setConnectionStatus("offline"); setStatusLabel(error.message);
|
||||
if (isPendingInteractionError(error)) {
|
||||
setStatusLabel("等待补充信息");
|
||||
showMapNotice({ id: "agent-stream-status", tone: "warning", title: "有待回答的问题", message: "请在对话中的提问卡片中选择或填写后提交,也可以取消提问。" });
|
||||
return;
|
||||
}
|
||||
checkAgentConnection();
|
||||
setStatusLabel(error.message);
|
||||
showMapNotice({ id: "agent-stream-status", tone: "error", title: "Agent 请求失败", message: error.message });
|
||||
},
|
||||
onFinish: (status) => {
|
||||
void refreshInteractionRequests();
|
||||
markLastAssistantStreamDone(runtime.chat.messages, setStreamRenderState);
|
||||
setConnectionStatus(status === "error" ? "offline" : "online");
|
||||
setStatusLabel(status === "error" ? runtime.error ?? "Agent 处理失败" : status === "aborted" ? "Agent 已停止" : "Agent 分析完成");
|
||||
if (status === "error") checkAgentConnection();
|
||||
setStatusLabel(status === "error" ? runtime.error ?? "Agent 处理失败" : status === "aborted" ? "Agent 已停止" : status === "waiting_input" ? "等待补充信息" : "Agent 分析完成");
|
||||
},
|
||||
onReconnect: () => {
|
||||
checkAgentConnection();
|
||||
setStatusLabel("连接已中断,正在恢复会话");
|
||||
},
|
||||
};
|
||||
return () => { runtime.handlers = undefined; };
|
||||
}, [handleDataPart, handleSessionStreamEvent, runtime]);
|
||||
}, [checkAgentConnection, handleDataPart, handleSessionStreamEvent, refreshInteractionRequests, runtime]);
|
||||
const loadHistorySession = useCallback(async (nextSessionId: string) => {
|
||||
const generation = ++loadingGenerationRef.current;
|
||||
let target = agentRuntimes(resources).find((entry) => entry.scope === scopeKey && entry.sessionId === nextSessionId);
|
||||
try {
|
||||
if (!target || target.error || (!runtimeRunning(target) && Date.now() - target.loadedAt >= 60_000)) {
|
||||
if (!target || target.error || target.connectionError || (!runtimeRunning(target) && Date.now() - target.loadedAt >= 60_000)) {
|
||||
const loaded = await resources.cache.load(JSON.stringify(["session", scopeKey, nextSessionId]),
|
||||
() => scopeClient.loadSession(nextSessionId, { messageLimit: 40, signal: AbortSignal.timeout(15_000) }), 60_000, { force: Boolean(target?.error) });
|
||||
if (!loaded) throw new Error("这个历史会话不存在或已被删除。");
|
||||
@@ -732,7 +826,6 @@ export function useWorkbenchAgent({
|
||||
activateRuntime(next);
|
||||
setTaskDiscussion(null);
|
||||
setStatusLabel(nextStatusLabel);
|
||||
setConnectionStatus("online");
|
||||
}, [activateRuntime, resources, scopeClient, scopeKey, transport]);
|
||||
|
||||
const selectTopic = (topicId: string | null) => {
|
||||
@@ -798,7 +891,9 @@ export function useWorkbenchAgent({
|
||||
return;
|
||||
}
|
||||
|
||||
if (streaming) {
|
||||
if (streaming || interactionRequests.awaitingInput) {
|
||||
const owningRuntime = runtimeRef.current;
|
||||
const owningSessionId = sessionIdRef.current;
|
||||
try {
|
||||
if (!sessionIdRef.current) throw new Error("Agent 正在建立会话,请稍后追加消息。");
|
||||
const receipt = await clientRef.current.submitResponseInput(sessionIdRef.current, normalizedPrompt, inputDelivery, `msg_${crypto.randomUUID().replaceAll("-", "")}`);
|
||||
@@ -808,15 +903,23 @@ export function useWorkbenchAgent({
|
||||
? [...current.filter((input) => input.id !== receipt.id), receipt]
|
||||
: current.filter((input) => input.id !== receipt.id), { revalidate: false })
|
||||
.then(() => refreshPendingInputs()).catch(() => {});
|
||||
return;
|
||||
} catch (error) {
|
||||
showMapNotice({ tone: "error", title: "追加消息失败", message: error instanceof Error ? error.message : "请稍后重试。" });
|
||||
throw error;
|
||||
if (error instanceof AgentResponseFinishedError) {
|
||||
await refreshInteractionRequests();
|
||||
if (runtimeRef.current !== owningRuntime || sessionIdRef.current !== owningSessionId) {
|
||||
throw new Error("原会话已切换,请回到原会话后重新发送。");
|
||||
}
|
||||
} else {
|
||||
showMapNotice({ tone: "error", title: "追加消息失败", message: error instanceof Error ? error.message : "请稍后重试。" });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setStatusLabel("Agent 正在分析");
|
||||
runtimeRef.current!.error = undefined;
|
||||
runtimeRef.current!.runStatus = "running";
|
||||
|
||||
await chat.sendMessage(
|
||||
{ text: normalizedPrompt },
|
||||
@@ -826,13 +929,13 @@ export function useWorkbenchAgent({
|
||||
topic_id: !sessionIdRef.current ? runtimeRef.current?.topicId ?? undefined : undefined,
|
||||
model: selectedModel || undefined,
|
||||
approval_mode: approvalMode,
|
||||
capabilities: frontendActionEnabledRef.current ? ["frontend-action@1"] : [],
|
||||
capabilities: frontendActionEnabledRef.current ? ["frontend-action@1", "host-question@1"] : ["host-question@1"],
|
||||
task_context: taskDiscussion?.sessionId === sessionIdRef.current ? taskDiscussion.context : undefined
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
[approvalMode, chat, inputDelivery, refreshPendingInputs, selectedModel, streaming, taskDiscussion]
|
||||
[approvalMode, chat, inputDelivery, interactionRequests.awaitingInput, refreshInteractionRequests, refreshPendingInputs, selectedModel, streaming, taskDiscussion]
|
||||
);
|
||||
|
||||
const triggerEvent = useCallback(async (trigger: AgentEventTriggerContext, prompt: string) => {
|
||||
@@ -846,17 +949,19 @@ export function useWorkbenchAgent({
|
||||
if (loaded.runStatus === "running" || loaded.isStreaming) resumeAgentRuntime(resources, target);
|
||||
}
|
||||
activateRuntime(target);
|
||||
setConnectionStatus("online");
|
||||
if (runtimeRunning(target) || target.chat.messages.length) return { sessionId: id, reused: true };
|
||||
setStatusLabel("Agent 正在调查水质投诉事件");
|
||||
void target.chat.sendMessage({ text: prompt }, { body: {
|
||||
session_id: id, model: selectedModel || undefined, approval_mode: approvalMode, trigger_context: trigger,
|
||||
capabilities: frontendActionEnabledRef.current ? ["frontend-action@1"] : [],
|
||||
capabilities: frontendActionEnabledRef.current ? ["frontend-action@1", "host-question@1"] : ["host-question@1"],
|
||||
} }).catch(() => {});
|
||||
return { sessionId: id, reused: reserved.event_duplicate === true };
|
||||
}, [activateRuntime, approvalMode, resources, scopeClient, scopeKey, selectedModel, transport]);
|
||||
|
||||
const stopPrompt = useCallback(() => {
|
||||
for (const entry of interactionRequests.entries) {
|
||||
if (entry.record.status === "pending") void interactionRequests.act(entry.record.interaction_id, "cancel");
|
||||
}
|
||||
chat.stop();
|
||||
stopSessionStreamSubscription();
|
||||
const activeSessionId = sessionIdRef.current;
|
||||
@@ -864,7 +969,7 @@ export function useWorkbenchAgent({
|
||||
void clientRef.current.abort(activeSessionId).then(() => refreshPendingInputs()).catch(() => undefined);
|
||||
}
|
||||
markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
|
||||
}, [chat, refreshPendingInputs, stopSessionStreamSubscription]);
|
||||
}, [chat, interactionRequests, refreshPendingInputs, stopSessionStreamSubscription]);
|
||||
|
||||
const replyPermission = useCallback(async (permission: AgentPermissionRequest, reply: AgentPermissionReply) => {
|
||||
const target = resources.activeAgent;
|
||||
@@ -933,6 +1038,7 @@ export function useWorkbenchAgent({
|
||||
inputDelivery,
|
||||
setInputDelivery,
|
||||
pendingInputs,
|
||||
interactionRequests,
|
||||
updateInputDelivery,
|
||||
withdrawInput,
|
||||
agentMessageInbox,
|
||||
@@ -946,6 +1052,7 @@ export function useWorkbenchAgent({
|
||||
openMobilePanel,
|
||||
closeMobilePanel,
|
||||
connectionStatus,
|
||||
connectionRecoveryVersion: recoveryVersion,
|
||||
panelCollapsing,
|
||||
panelOpen,
|
||||
personaState,
|
||||
@@ -1063,9 +1170,9 @@ function createWorkbenchAgentTransport(client: AgentApiClient, access?: Workbenc
|
||||
const model = resolveAgentModelSelection(catalog, readBodyString(body, "model") ?? "");
|
||||
if (!model) throw new Error("Agent 后端当前没有可用模型,请检查模型配置。");
|
||||
return { body: createResponseRequest(messages, {
|
||||
conversation: readBodyString(body, "session_id"), model, topicId: readBodyString(body, "topic_id"),
|
||||
conversation: readBodyString(body, "session_id"), interactionId: readBodyString(body, "interaction_id"), model, topicId: readBodyString(body, "topic_id"),
|
||||
approvalMode: readBodyString(body, "approval_mode") ?? "request",
|
||||
capabilities: Array.isArray(body?.capabilities) ? body.capabilities.filter((value): value is string => value === "frontend-action@1") : [], triggerContext: body?.trigger_context, taskContext: body?.task_context,
|
||||
capabilities: Array.isArray(body?.capabilities) ? body.capabilities.filter((value): value is string => value === "frontend-action@1" || value === "host-question@1") : [], triggerContext: body?.trigger_context, taskContext: body?.task_context,
|
||||
}) };
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user