feat: harden support, localize knowledge and add operator availability [skip ci]
Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.
Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.
Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.
Expected source tree: 0a4a7528e9.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// Modified in the independent hardening fork; see docs/hardening/README.md.
|
||||
// Modified for AgentDeskFixes: capture operator recipients and preserve failed message drafts.
|
||||
"use client";
|
||||
|
||||
import {
|
||||
@@ -61,6 +63,7 @@ import {
|
||||
type AIWorkflowRun,
|
||||
} from "@/lib/api/admin";
|
||||
import { readSession } from "@/lib/auth";
|
||||
import { createMessageEditorDraftStore } from "@/lib/message-editor-drafts";
|
||||
import { renderIMMessageHTML } from "@/lib/im-message";
|
||||
import {
|
||||
agentConversationSelectors,
|
||||
@@ -177,6 +180,8 @@ export function ChatPanel() {
|
||||
null,
|
||||
);
|
||||
const shouldStickToBottomRef = useRef(true);
|
||||
const [draftStore] = useState(createMessageEditorDraftStore);
|
||||
useEffect(() => () => draftStore.clear(), [draftStore]);
|
||||
const [claiming, setClaiming] = useState(false);
|
||||
const [claimDialogOpen, setClaimDialogOpen] = useState(false);
|
||||
const [transferDialogOpen, setTransferDialogOpen] = useState(false);
|
||||
@@ -314,12 +319,19 @@ export function ChatPanel() {
|
||||
};
|
||||
|
||||
const handleSend = async (html: string) => {
|
||||
if (!conversation || sending || isClosedConversation) return;
|
||||
// Bind the displayed draft to its recipient before the store reads selection.
|
||||
const recipientId = conversation?.id;
|
||||
try {
|
||||
if (!recipientId || sending || isClosedConversation ||
|
||||
useAgentConversationsStore.getState().selectedConversationId !== recipientId) {
|
||||
throw new Error(t("conversation.sendMessageFailed"));
|
||||
}
|
||||
shouldStickToBottomRef.current = true;
|
||||
await sendMessage(html);
|
||||
const message = await sendMessage(html, recipientId);
|
||||
if (!message) throw new Error(t("conversation.sendMessageFailed"));
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : t("conversation.sendMessageFailed"));
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -369,7 +381,7 @@ export function ChatPanel() {
|
||||
setWorkflowRunLoading(false);
|
||||
}
|
||||
},
|
||||
[],
|
||||
[t],
|
||||
);
|
||||
|
||||
if (!conversation) {
|
||||
@@ -495,20 +507,28 @@ export function ChatPanel() {
|
||||
<div className="flex h-full min-h-0 flex-col">
|
||||
<div className="min-h-0 flex-1">
|
||||
<AgentMessageEditor
|
||||
disabled={!conversation || sending}
|
||||
draftStore={draftStore}
|
||||
disabled={!conversation}
|
||||
sending={sending}
|
||||
uploadingAsset={uploadingAsset}
|
||||
onSend={handleSend}
|
||||
onUploadImage={async (file) => {
|
||||
shouldStickToBottomRef.current = true;
|
||||
const uploaded = await uploadImage(file);
|
||||
return uploaded;
|
||||
try {
|
||||
return await uploadImage(file, conversation.id);
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : t("upload.imageUploadFailed"));
|
||||
throw error;
|
||||
}
|
||||
}}
|
||||
onSendAttachment={async (file) => {
|
||||
shouldStickToBottomRef.current = true;
|
||||
try {
|
||||
await sendAttachment(file);
|
||||
const message = await sendAttachment(file, conversation.id);
|
||||
if (!message) throw new Error(t("conversation.sendAttachmentFailed"));
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : t("conversation.sendAttachmentFailed"));
|
||||
throw error;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user