213 lines
6.8 KiB
TypeScript
213 lines
6.8 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 AionUi (aionui.com)
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { normalizeDbMessage } from '@/renderer/pages/conversation/Messages/hooks';
|
|
import type { IMessageText, IMessageTips } from '@/common/chat/chatLib';
|
|
|
|
describe('normalizeDbMessage', () => {
|
|
it('keeps persisted info tip localization metadata from db content', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'tip-info',
|
|
type: 'tips',
|
|
conversation_id: 'conversation-1',
|
|
position: 'center',
|
|
status: 'finish',
|
|
content: JSON.stringify({
|
|
content: '',
|
|
type: 'info',
|
|
code: 'ACP_EMPTY_TURN',
|
|
params: {
|
|
provider: 'OpenCode',
|
|
},
|
|
}),
|
|
} as unknown as IMessageTips) as IMessageTips;
|
|
|
|
expect(normalized.content).toEqual({
|
|
content: '',
|
|
type: 'info',
|
|
code: 'ACP_EMPTY_TURN',
|
|
params: {
|
|
provider: 'OpenCode',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('keeps structured error metadata from persisted tips', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'tip-structured',
|
|
type: 'tips',
|
|
conversation_id: 'conversation-1',
|
|
position: 'center',
|
|
status: 'error',
|
|
content: JSON.stringify({
|
|
content: 'The upstream Agent failed while handling the request',
|
|
type: 'error',
|
|
source: 'send_failed',
|
|
code: 'BAD_GATEWAY',
|
|
error: {
|
|
message: 'The upstream Agent failed while handling the request',
|
|
code: 'UNKNOWN_UPSTREAM_ERROR',
|
|
ownership: 'unknown_upstream',
|
|
detail: 'ACP init failed: config file is invalid',
|
|
retryable: true,
|
|
feedback_recommended: true,
|
|
resolution: {
|
|
kind: 'start_new_session',
|
|
target: 'new_conversation',
|
|
},
|
|
},
|
|
}),
|
|
} as unknown as IMessageTips) as IMessageTips;
|
|
|
|
expect(normalized.content.error).toEqual({
|
|
message: 'The upstream Agent failed while handling the request',
|
|
code: 'UNKNOWN_UPSTREAM_ERROR',
|
|
ownership: 'unknown_upstream',
|
|
detail: 'ACP init failed: config file is invalid',
|
|
retryable: true,
|
|
feedback_recommended: true,
|
|
resolution: {
|
|
kind: 'start_new_session',
|
|
target: 'new_conversation',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('restores persisted send failure tips as structured agent errors', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'tip-1',
|
|
type: 'tips',
|
|
conversation_id: 'conversation-1',
|
|
position: 'center',
|
|
status: 'error',
|
|
content: JSON.stringify({
|
|
content: 'Bad gateway: ACP init failed: config file is invalid',
|
|
type: 'error',
|
|
source: 'send_failed',
|
|
code: 'BAD_GATEWAY',
|
|
}),
|
|
} as unknown as IMessageTips) as IMessageTips;
|
|
|
|
expect(normalized.content).toEqual({
|
|
content: 'Bad gateway: ACP init failed: config file is invalid',
|
|
type: 'error',
|
|
error: {
|
|
message: 'Bad gateway: ACP init failed: config file is invalid',
|
|
code: 'UNKNOWN_UPSTREAM_ERROR',
|
|
ownership: 'unknown_upstream',
|
|
detail: 'Bad gateway: ACP init failed: config file is invalid',
|
|
retryable: true,
|
|
feedback_recommended: true,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('prefers persisted workspace runtime errors over legacy unknown-upstream payloads', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'tip-runtime-workspace',
|
|
type: 'tips',
|
|
conversation_id: 'conversation-1',
|
|
position: 'center',
|
|
status: 'error',
|
|
content: JSON.stringify({
|
|
content: 'The current Agent failed to run in this workspace path',
|
|
type: 'error',
|
|
source: 'send_failed',
|
|
code: 'WORKSPACE_PATH_CONTAINS_WHITESPACE_RUNTIME_UNSUPPORTED',
|
|
details: {
|
|
workspace_path: '/Users/zhoukai/Documents/Archive ',
|
|
},
|
|
error: {
|
|
message: 'The current Agent failed to run in this workspace path',
|
|
code: 'UNKNOWN_UPSTREAM_ERROR',
|
|
ownership: 'unknown_upstream',
|
|
detail: '/Users/zhoukai/Documents/Archive . Make sure the workspace path exists and is accessible.',
|
|
retryable: true,
|
|
feedback_recommended: true,
|
|
},
|
|
}),
|
|
} as unknown as IMessageTips) as IMessageTips;
|
|
|
|
expect(normalized.content.error).toEqual({
|
|
message: 'The current Agent failed to run in this workspace path',
|
|
code: 'WORKSPACE_PATH_RUNTIME_UNAVAILABLE',
|
|
ownership: 'aionui',
|
|
detail: '/Users/zhoukai/Documents/Archive . Make sure the workspace path exists and is accessible.',
|
|
workspacePath: '/Users/zhoukai/Documents/Archive ',
|
|
retryable: false,
|
|
feedback_recommended: false,
|
|
});
|
|
});
|
|
|
|
it('normalizes team metadata when persisted text content is already an object', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'team-message-object',
|
|
type: 'text',
|
|
conversation_id: 'leader-conversation-1',
|
|
position: 'left',
|
|
status: 'finish',
|
|
content: {
|
|
content: '[Claude Assistant] idle',
|
|
teammate_message: true,
|
|
sender_name: 'Claude Assistant',
|
|
sender_backend: 'claude',
|
|
sender_conversation_id: 'teammate-conversation-1',
|
|
},
|
|
} as unknown as IMessageText) as IMessageText;
|
|
|
|
expect(normalized.content).toEqual({
|
|
content: '[Claude Assistant] idle',
|
|
teammateMessage: true,
|
|
senderName: 'Claude Assistant',
|
|
senderAgentType: 'claude',
|
|
senderConversationId: 'teammate-conversation-1',
|
|
});
|
|
});
|
|
|
|
it('normalizes team metadata when persisted text content is a JSON string', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'team-message-json',
|
|
type: 'text',
|
|
conversation_id: 'leader-conversation-1',
|
|
position: 'left',
|
|
status: 'finish',
|
|
content: JSON.stringify({
|
|
content: '[Codex Assistant] idle',
|
|
teammate_message: true,
|
|
sender_name: 'Codex Assistant',
|
|
sender_backend: 'codex',
|
|
sender_conversation_id: 'teammate-conversation-2',
|
|
}),
|
|
} as unknown as IMessageText) as IMessageText;
|
|
|
|
expect(normalized.content).toEqual({
|
|
content: '[Codex Assistant] idle',
|
|
teammateMessage: true,
|
|
senderName: 'Codex Assistant',
|
|
senderAgentType: 'codex',
|
|
senderConversationId: 'teammate-conversation-2',
|
|
});
|
|
});
|
|
|
|
it('keeps ordinary recovered text messages as plain text content', () => {
|
|
const normalized = normalizeDbMessage({
|
|
id: 'ordinary-text',
|
|
type: 'text',
|
|
conversation_id: 'conversation-1',
|
|
position: 'left',
|
|
status: 'finish',
|
|
content: {
|
|
content: 'ordinary assistant response',
|
|
},
|
|
} as unknown as IMessageText) as IMessageText;
|
|
|
|
expect(normalized.content).toEqual({
|
|
content: 'ordinary assistant response',
|
|
});
|
|
});
|
|
});
|