persist error message in oss doc

This commit is contained in:
2026-07-16 17:18:08 +08:00
parent 9dc65e1d47
commit ca4bf6db5e
9 changed files with 134 additions and 37 deletions
@@ -1,4 +1,7 @@
import type { EditorAgentMessage } from '@/packages/shared/src/contracts';
import {
EDITOR_AGENT_ERROR_MESSAGE_PREFIX,
type EditorAgentMessage,
} from '@/packages/shared/src/contracts';
import AttachmentChip from '@/src/components/image-editor/EditorAgentConversation/AttachmentChip.tsx';
import { attachmentKey } from '@/src/components/image-editor/EditorAgentConversation/common.ts';
import { PendingToolCall } from '@/src/components/image-editor/EditorAgentConversation/PendingToolCall.tsx';
@@ -51,7 +54,14 @@ export function MessageBubble({
onCancelToolCall,
onJobCompleted,
}: MessageBubbleProps) {
if (message.role === 'system' && !message.toolCall) {
const systemErrorText =
message.role === 'system' &&
!message.toolCall &&
message.text.startsWith(EDITOR_AGENT_ERROR_MESSAGE_PREFIX)
? message.text.slice(EDITOR_AGENT_ERROR_MESSAGE_PREFIX.length)
: null;
if (message.role === 'system' && !message.toolCall && systemErrorText === null) {
return null;
}
if (
@@ -73,29 +83,36 @@ export function MessageBubble({
const isUser = message.role === 'user';
const isSystem = message.role === 'system';
const isSystemError = systemErrorText !== null;
return (
<article
className={`flex ${isUser ? 'justify-end' : 'justify-start'}`}
aria-label={
isSystem ? 'Agent操作' : `${messageRoleLabel(message.role)}消息`
isSystemError
? 'Agent错误'
: isSystem
? 'Agent操作'
: `${messageRoleLabel(message.role)}消息`
}
>
<div
className={
isSystem
isSystem && !isSystemError
? 'max-w-[86%]'
: `max-w-[86%] rounded-3xl px-3.5 py-3 text-sm leading-6 shadow-sm ${
isUser
? 'bg-slate-900 text-white'
: message.toolCall?.status === 'failed'
: isSystemError || message.toolCall?.status === 'failed'
? 'border border-red-200 bg-red-50 text-red-700'
: 'border border-slate-200 bg-white text-slate-700'
}`
}
>
{!isSystem && message.text ? (
<div className="whitespace-pre-wrap break-words">{message.text}</div>
{(!isSystem || isSystemError) && (systemErrorText ?? message.text) ? (
<div className="whitespace-pre-wrap break-words">
{systemErrorText ?? message.text}
</div>
) : null}
{!isSystem && message.attachments.length ? (
<div className="mt-2 flex flex-wrap gap-1.5">
@@ -301,7 +301,7 @@ describe('useEditorAgentConversation', () => {
);
});
it('handles backend error responses', async () => {
it('applies persisted backend planning errors as system messages', async () => {
const client = createClient();
vi.mocked(client.sendMessage).mockResolvedValue({
conversation: {
@@ -310,8 +310,17 @@ describe('useEditorAgentConversation', () => {
title: '这是美术素材',
updatedAt: '2026-07-03T00:00:01.000Z',
},
deltaMessages: [],
errorMessage: 'LLM 未配置,无法处理这句话。',
deltaMessages: [
{
id: 2,
role: 'system',
text: 'ERROR LLM 未配置,无法处理这句话。',
attachments: [],
toolCall: null,
createdAt: '2026-07-16T00:00:01.000Z',
},
],
errorMessage: null,
} as EditorAgentMessageResponse);
const { result } = renderHook(() =>
useEditorAgentConversation({ projectId: 'project-1', client }),
@@ -327,7 +336,15 @@ describe('useEditorAgentConversation', () => {
await result.current.sendMessage('这是美术素材');
});
expect(result.current.errorMessage).toBe('LLM 未配置,无法处理这句话。');
expect(result.current.errorMessage).toBeNull();
expect(result.current.messages).toEqual(
expect.arrayContaining([
expect.objectContaining({
role: 'system',
text: 'ERROR LLM 未配置,无法处理这句话。',
}),
]),
);
});
it('confirms a pending tool call, replaces its message and requests a canvas refresh', async () => {