fix objectKey mismatch
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
- 附件选择弹窗使用 `PlatformToolModalShell` 承接 portal 主题变量和不透明 panel 背景;不能直接把未注入 `platform-theme` 的 `UnifiedModal` portal 到 `document.body`,否则 `--platform-modal-fill` 失效后面板会变透明。
|
||||
- 应用后附件以胶囊 chip 挂在输入框上方;发出的消息内附件渲染为纯文本胶囊 chip(名称 + 小图标),**默认无缩略图,鼠标悬浮才浮出缩略图预览**。
|
||||
- 附件领域形状:统一为画布资源 / 素材库对象引用(`resourceId` / `assetId` + 可选 `objectKey`),不存在只属于对话的第三种图;单条消息上限 9 张(前后端共同校验)。前端可携带展示用 `imageSrc` / `thumbnailSrc`,后端必须按当前工程和当前账号重新归一、校验归属与 `objectKey`。
|
||||
- 输入区附件临时状态统一收口到 `useConversationAttachments`,选择弹窗由独立的 `AttachmentPicker` 负责纯展示;选择、引用、粘贴上传完成、移除、发送清空和失败恢复都必须经同一最新状态更新入口。发送失败时,已发送附件必须与等待期间新增的附件去重合并,不得因输入区已非空而丢弃;合并后超过 9 张时优先保留等待期间的最新附件,不恢复失败请求的附件,并立即显示上限错误。异步粘贴完成时基于当时的最新附件去重并重新校验 9 张上限,不能用上传开始时捕获的旧列表覆盖期间新增的引用。
|
||||
- 输入区附件临时状态统一收口到 `useConversationAttachments`,选择弹窗由独立的 `AttachmentPicker` 负责纯展示;选择、引用、粘贴上传完成、移除、发送清空和失败恢复都必须经同一最新状态更新入口。引用历史消息附件时先保留消息中的展示快照,最终发送前再按 `source + referenceId` 从当前画布和素材库选项刷新,避免提前刷新后又被失败恢复的旧快照覆盖。发送失败时,已发送附件必须与等待期间新增的附件去重合并,不得因输入区已非空而丢弃;合并后超过 9 张时优先保留等待期间的最新附件,不恢复失败请求的附件,并立即显示上限错误。异步粘贴完成时基于当时的最新附件去重并重新校验 9 张上限,不能用上传开始时捕获的旧列表覆盖期间新增的引用。
|
||||
|
||||
## 工具调用确认展示契约
|
||||
|
||||
|
||||
+5
-2
@@ -617,7 +617,7 @@ describe('EditorAgentConversationPanelView', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('prefers the current attachment matched by source and reference id', async () => {
|
||||
it('refreshes an attachment matched by source and reference id when sending', async () => {
|
||||
const client = createClient();
|
||||
vi.mocked(client.getConversation).mockResolvedValue({
|
||||
conversationId: 'conversation-1',
|
||||
@@ -673,7 +673,10 @@ describe('EditorAgentConversationPanelView', () => {
|
||||
const historicalAttachment = await screen.findByText('旧版附件');
|
||||
fireEvent.contextMenu(historicalAttachment.closest('.group')!);
|
||||
fireEvent.click(screen.getByRole('menuitem', { name: '引用' }));
|
||||
expect(await screen.findByText('最新附件')).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByText('旧版附件')).toHaveLength(2);
|
||||
});
|
||||
expect(screen.queryByText('最新附件')).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '发送' }));
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -259,22 +259,22 @@ export function useConversationAttachments({
|
||||
|
||||
const referenceContextAsset = useCallback(
|
||||
(asset: EditorAgentContextAsset) => {
|
||||
const directAttachment: EditorAgentAttachmentRef | undefined =
|
||||
asset.kind === 'attachment'
|
||||
? {
|
||||
source: asset.source,
|
||||
referenceId: asset.referenceId,
|
||||
objectKey: asset.objectKey,
|
||||
imageSrc: asset.imageSrc,
|
||||
thumbnailSrc: asset.thumbnailSrc,
|
||||
label: asset.label,
|
||||
width: asset.width,
|
||||
height: asset.height,
|
||||
}
|
||||
: undefined;
|
||||
const referenceOption = directAttachment
|
||||
? attachmentOptionsByKey.get(attachmentKey(directAttachment))
|
||||
: undefined;
|
||||
if (asset.kind === 'attachment') {
|
||||
const directAttachment: EditorAgentAttachmentRef = {
|
||||
source: asset.source,
|
||||
referenceId: asset.referenceId,
|
||||
objectKey: asset.objectKey,
|
||||
imageSrc: asset.imageSrc,
|
||||
thumbnailSrc: asset.thumbnailSrc,
|
||||
label: asset.label,
|
||||
width: asset.width,
|
||||
height: asset.height,
|
||||
};
|
||||
return directAttachment.referenceId.trim() &&
|
||||
directAttachment.imageSrc.trim()
|
||||
? appendAttachments([directAttachment])
|
||||
: false;
|
||||
}
|
||||
const objectKey = asset.objectKey?.trim();
|
||||
const mediaSrc = contextAssetMediaSrc(asset).trim();
|
||||
const objectKeyOption = objectKey
|
||||
@@ -290,14 +290,13 @@ export function useConversationAttachments({
|
||||
attachment.thumbnailSrc?.trim() === mediaSrc
|
||||
);
|
||||
});
|
||||
const matchedAttachment =
|
||||
referenceOption?.attachment || option?.attachment || directAttachment;
|
||||
const matchedAttachment = option?.attachment;
|
||||
return matchedAttachment?.referenceId.trim() &&
|
||||
matchedAttachment.imageSrc.trim()
|
||||
? appendAttachments([matchedAttachment])
|
||||
: false;
|
||||
},
|
||||
[appendAttachments, attachmentOptions, attachmentOptionsByKey],
|
||||
[appendAttachments, attachmentOptions],
|
||||
);
|
||||
|
||||
const handleInputPaste = useCallback(
|
||||
@@ -361,9 +360,14 @@ export function useConversationAttachments({
|
||||
|
||||
const consumeAttachments = useCallback(() => {
|
||||
const currentAttachments = attachmentsRef.current;
|
||||
const refreshedAttachments = currentAttachments.map(
|
||||
(attachment) =>
|
||||
attachmentOptionsByKey.get(attachmentKey(attachment))?.attachment ??
|
||||
attachment,
|
||||
);
|
||||
updateAttachments([]);
|
||||
return currentAttachments;
|
||||
}, [updateAttachments]);
|
||||
return refreshedAttachments;
|
||||
}, [attachmentOptionsByKey, updateAttachments]);
|
||||
|
||||
const restoreAttachments = useCallback(
|
||||
(failedAttachments: EditorAgentAttachmentRef[]) => {
|
||||
|
||||
Reference in New Issue
Block a user