fix(pipelines): retain debug chat image history

This commit is contained in:
RockChinQ
2026-08-26 00:32:03 +08:00
parent 94fd3d274c
commit 47f5515fa9
7 changed files with 105 additions and 36 deletions
@@ -457,7 +457,7 @@ export default function DebugDialog({
return;
}
const messageChain = [];
const messageChain: MessageChainComponent[] = [];
// Add quoted message if present
if (quotedMessage) {
@@ -511,17 +511,21 @@ export default function DebugDialog({
type: 'Image',
path: result.file_key,
});
} else {
} else if (attachment.kind === 'voice') {
// Voice / File go through the generic document upload endpoint,
// which returns a storage key the backend resolves into the
// sandbox inbox just like images.
const result = await httpClient.uploadDocumentFile(attachment.file);
messageChain.push({
type: attachment.kind === 'voice' ? 'Voice' : 'File',
type: 'Voice',
path: result.file_id,
...(attachment.kind === 'file'
? { name: attachment.file.name }
: {}),
});
} else {
const result = await httpClient.uploadDocumentFile(attachment.file);
messageChain.push({
type: 'File',
path: result.file_id,
name: attachment.file.name,
});
}
} catch (error) {
+1 -1
View File
@@ -19,7 +19,7 @@ export interface Plain extends MessageComponent {
// Quote component
export interface Quote extends MessageComponent {
type: 'Quote';
id?: number;
id?: number | string;
group_id?: number | string;
sender_id?: number | string;
target_id?: number | string;
@@ -3,12 +3,13 @@
* 用于管理WebSocket连接和消息处理
*/
import { getActiveWorkspaceUuid } from '@/app/infra/http/workspaceContext';
import type { MessageChainComponent } from '@/app/infra/entities/message';
export interface WebSocketMessage {
id: number;
role: 'user' | 'assistant';
content: string;
message_chain: Array<{ type: string; text?: string; target?: string }>;
message_chain: MessageChainComponent[];
timestamp: string;
is_final?: boolean;
connection_id?: string;
@@ -16,7 +17,12 @@ export interface WebSocketMessage {
export interface WebSocketResponse {
type:
'connected' | 'response' | 'user_message' | 'pong' | 'broadcast' | 'error';
| 'connected'
| 'response'
| 'user_message'
| 'pong'
| 'broadcast'
| 'error';
connection_id?: string;
pipeline_uuid?: string;
session_type?: string;
@@ -262,7 +268,7 @@ export class WebSocketClient {
* 发送消息
*/
public sendMessage(
messageChain: Array<{ type: string; text?: string; target?: string }>,
messageChain: MessageChainComponent[],
stream: boolean = true,
) {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
@@ -226,6 +226,31 @@ test.describe('processor detail workbench', () => {
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
const debugImageKey =
'v1/mock-instance/workspace-default/1/upload_image/mock-owner/debug-image.png';
const debugImageBytes = Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9Zl1sAAAAASUVORK5CYII=',
'base64',
);
await page.route('**/api/v1/files/images', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
code: 0,
message: 'ok',
data: { file_key: debugImageKey },
timestamp: Date.now(),
}),
});
});
await page.route('**/api/v1/files/image/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'image/png',
body: debugImageBytes,
});
});
await page.routeWebSocket('**/api/v1/pipelines/**/ws/connect**', (ws) => {
ws.onMessage((raw) => {
const message = JSON.parse(String(raw));
@@ -238,6 +263,21 @@ test.describe('processor detail workbench', () => {
session_type: 'person',
}),
);
} else if (message.type === 'message') {
ws.send(
JSON.stringify({
type: 'user_message',
session_type: 'person',
data: {
id: 1,
role: 'user',
content: 'Describe this image',
message_chain: message.message,
timestamp: new Date().toISOString(),
is_final: true,
},
}),
);
}
});
});
@@ -303,6 +343,21 @@ test.describe('processor detail workbench', () => {
expect(Math.abs(sendBox!.y - inputBox!.y)).toBeLessThanOrEqual(1);
expect(toolbarBox!.y).toBeLessThan(emptyStateBox!.y);
await composer.locator('input[type="file"]').setInputFiles({
name: 'debug-image.png',
mimeType: 'image/png',
buffer: debugImageBytes,
});
await expect(
debugPanel.locator('[data-debug-chat-attachment-preview="true"]'),
).toBeVisible();
await messageInput.fill('Describe this image');
await sendButton.click();
await expect(
debugPanel.locator('[data-debug-chat-message-image="true"]'),
).toBeVisible();
await expect(debugPanel.getByText('Describe this image')).toBeVisible();
const streamSwitchBox = await composer.getByRole('switch').boundingBox();
const resetBox = await resetButton.boundingBox();
expect(streamSwitchBox).not.toBeNull();