replace onEditorAgentGenerationResult with onEditorAgentCanvasRefreshRequested and update related logic
This commit is contained in:
@@ -34,7 +34,7 @@ type EditorAgentGetConversation =
|
||||
EditorAgentConversationClient['getConversation'];
|
||||
type EditorAgentDeleteConversation =
|
||||
EditorAgentConversationClient['deleteConversation'];
|
||||
type EditorAgentStreamMessage = EditorAgentConversationClient['streamMessage'];
|
||||
type EditorAgentStreamMessage = EditorAgentConversationClient['sendMessage'];
|
||||
type EditorAgentConversationSummary = Awaited<
|
||||
ReturnType<EditorAgentListConversations>
|
||||
>[number];
|
||||
@@ -68,8 +68,6 @@ const getEditorAgentConversationMock = vi.hoisted(() =>
|
||||
>(async () => ({
|
||||
conversationId: 'editor-agent-conv-test',
|
||||
projectId: 'editor-project-default',
|
||||
title: '画布 Agent',
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
updatedAt: '2026-07-03T00:00:00.000Z',
|
||||
messages: [],
|
||||
})),
|
||||
@@ -86,12 +84,17 @@ const deleteEditorAgentConversationMock = vi.hoisted(() =>
|
||||
updatedAt: '2026-07-03T00:00:00.000Z',
|
||||
})),
|
||||
);
|
||||
const streamEditorAgentMessageMock = vi.hoisted(() =>
|
||||
const sendEditorAgentMessageMock = vi.hoisted(() =>
|
||||
vi.fn<
|
||||
Parameters<EditorAgentStreamMessage>,
|
||||
ReturnType<EditorAgentStreamMessage>
|
||||
>(async () => undefined),
|
||||
>(async () => ({
|
||||
deltaMessages: [],
|
||||
errorMessage: null,
|
||||
})),
|
||||
);
|
||||
const confirmEditorAgentToolCallMock = vi.hoisted(() => vi.fn());
|
||||
const cancelEditorAgentToolCallMock = vi.hoisted(() => vi.fn());
|
||||
const generateEditorImageMock = vi.hoisted(() => vi.fn());
|
||||
const generateEditorIconSpritesheetMock = vi.hoisted(() => vi.fn());
|
||||
const generateEditorCharacterAnimationMock = vi.hoisted(() => vi.fn());
|
||||
@@ -145,11 +148,13 @@ vi.mock('../../services/frontendRuntimeConfigService', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('../../services/image-editor/editorAgentClient', () => ({
|
||||
cancelEditorAgentToolCall: cancelEditorAgentToolCallMock,
|
||||
confirmEditorAgentToolCall: confirmEditorAgentToolCallMock,
|
||||
createEditorAgentConversation: createEditorAgentConversationMock,
|
||||
deleteEditorAgentConversation: deleteEditorAgentConversationMock,
|
||||
getEditorAgentConversation: getEditorAgentConversationMock,
|
||||
listEditorAgentConversations: listEditorAgentConversationsMock,
|
||||
streamEditorAgentMessage: streamEditorAgentMessageMock,
|
||||
sendEditorAgentMessage: sendEditorAgentMessageMock,
|
||||
}));
|
||||
|
||||
function createEditorAgentConversationSummary(
|
||||
@@ -158,8 +163,6 @@ function createEditorAgentConversationSummary(
|
||||
return {
|
||||
conversationId: 'editor-agent-conv-test',
|
||||
projectId: 'editor-project-default',
|
||||
title: '画布 Agent',
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
updatedAt: '2026-07-03T00:00:00.000Z',
|
||||
...overrides,
|
||||
};
|
||||
@@ -171,33 +174,30 @@ function createEditorAgentDetailWithGeneration(
|
||||
const summary = createEditorAgentConversationSummary();
|
||||
return {
|
||||
...summary,
|
||||
title: '画布 Agent',
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
id: 'agent-message-result',
|
||||
role: 'assistant',
|
||||
kind: 'chat',
|
||||
text: '生成完成',
|
||||
id: 1,
|
||||
role: 'system',
|
||||
text: 'internal completed tool output',
|
||||
attachments: [],
|
||||
generations: [
|
||||
{
|
||||
toolCallId: 'agent-tool-call-1',
|
||||
toolName: 'generate_image',
|
||||
taskId: 'task-agent-1',
|
||||
status: 'completed',
|
||||
model: 'gpt-image-2',
|
||||
images: [
|
||||
{
|
||||
resourceId,
|
||||
imageSrc: '/agent-result.png',
|
||||
thumbnailSrc: '/agent-result-thumb.png',
|
||||
width: 512,
|
||||
height: 512,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
],
|
||||
status: 'completed',
|
||||
toolCall: {
|
||||
toolName: 'generate_image',
|
||||
summary: '',
|
||||
status: 'completed',
|
||||
args: {},
|
||||
images: [
|
||||
{
|
||||
resourceId,
|
||||
imageSrc: '/agent-result.png',
|
||||
thumbnailSrc: '/agent-result-thumb.png',
|
||||
width: 512,
|
||||
height: 512,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
createdAt: '2026-07-03T00:00:01.000Z',
|
||||
},
|
||||
],
|
||||
@@ -260,16 +260,25 @@ describe('ImageCanvasEditorView', () => {
|
||||
...createEditorAgentConversationSummary({
|
||||
conversationId: 'editor-agent-conv-created',
|
||||
}),
|
||||
title: '画布 Agent',
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
messages: [],
|
||||
});
|
||||
getEditorAgentConversationMock.mockResolvedValue({
|
||||
...createEditorAgentConversationSummary(),
|
||||
title: '画布 Agent',
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
messages: [],
|
||||
});
|
||||
deleteEditorAgentConversationMock.mockResolvedValue(
|
||||
createEditorAgentConversationSummary(),
|
||||
);
|
||||
streamEditorAgentMessageMock.mockResolvedValue(undefined);
|
||||
sendEditorAgentMessageMock.mockResolvedValue({
|
||||
deltaMessages: [],
|
||||
errorMessage: null,
|
||||
});
|
||||
confirmEditorAgentToolCallMock.mockReset();
|
||||
cancelEditorAgentToolCallMock.mockReset();
|
||||
getPlatformProfileDashboardMock.mockResolvedValue({
|
||||
walletBalance: 1234,
|
||||
totalPlayTimeMs: 0,
|
||||
@@ -283,7 +292,9 @@ describe('ImageCanvasEditorView', () => {
|
||||
createEditorAgentConversationMock.mockReset();
|
||||
getEditorAgentConversationMock.mockReset();
|
||||
deleteEditorAgentConversationMock.mockReset();
|
||||
streamEditorAgentMessageMock.mockReset();
|
||||
sendEditorAgentMessageMock.mockReset();
|
||||
confirmEditorAgentToolCallMock.mockReset();
|
||||
cancelEditorAgentToolCallMock.mockReset();
|
||||
getPlatformProfileDashboardMock.mockReset();
|
||||
loadFrontendRuntimeConfigMock.mockReset();
|
||||
});
|
||||
@@ -1436,9 +1447,7 @@ describe('ImageCanvasEditorView', () => {
|
||||
render(<ImageCanvasEditorView />);
|
||||
|
||||
expect(screen.queryByRole('button', { name: '画布 Agent' })).toBeNull();
|
||||
expect(
|
||||
screen.queryByRole('button', { name: '打开画布 Agent' }),
|
||||
).toBeNull();
|
||||
expect(screen.queryByRole('button', { name: '打开画布 Agent' })).toBeNull();
|
||||
expect(screen.queryByLabelText('发送给画布 Agent')).toBeNull();
|
||||
expect(listEditorAgentConversationsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -1827,46 +1836,55 @@ describe('ImageCanvasEditorView', () => {
|
||||
]);
|
||||
getEditorAgentConversationMock.mockResolvedValueOnce({
|
||||
...createEditorAgentConversationSummary(),
|
||||
messages: [],
|
||||
title: '画布 Agent',
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
id: 0,
|
||||
role: 'system',
|
||||
text: 'internal pending tool prompt',
|
||||
attachments: [],
|
||||
toolCall: {
|
||||
toolName: 'edit-image',
|
||||
summary: '',
|
||||
status: 'pending_confirmation',
|
||||
args: {
|
||||
object_image_id: 'source-image',
|
||||
prompt: '把图片换成像素风',
|
||||
},
|
||||
images: [],
|
||||
error: null,
|
||||
},
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
},
|
||||
],
|
||||
});
|
||||
confirmEditorAgentToolCallMock.mockImplementation(async () => {
|
||||
showGeneratedAsset = true;
|
||||
return {
|
||||
id: 0,
|
||||
role: 'system',
|
||||
text: 'internal completed tool output',
|
||||
attachments: [],
|
||||
toolCall: {
|
||||
toolName: 'edit-image',
|
||||
summary: '',
|
||||
status: 'completed',
|
||||
args: {},
|
||||
images: [
|
||||
{
|
||||
resourceId: null,
|
||||
imageSrc: '/agent-stream.png',
|
||||
thumbnailSrc: null,
|
||||
width: 512,
|
||||
height: 512,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
createdAt: '2026-07-03T00:00:00.000Z',
|
||||
};
|
||||
});
|
||||
streamEditorAgentMessageMock.mockImplementation(
|
||||
async (conversationId, _payload, options) => {
|
||||
options.onEvent?.({
|
||||
event: 'message_delta',
|
||||
data: {
|
||||
conversationId,
|
||||
messageId: 'assistant-agent-stream',
|
||||
role: 'assistant',
|
||||
kind: 'chat',
|
||||
textDelta: '我来生成图片。',
|
||||
},
|
||||
});
|
||||
showGeneratedAsset = true;
|
||||
options.onEvent?.({
|
||||
event: 'generation_result',
|
||||
data: {
|
||||
conversationId,
|
||||
messageId: 'assistant-agent-stream',
|
||||
toolCallId: 'tool-call-agent-stream',
|
||||
toolName: 'generate_image',
|
||||
model: 'gpt-image-2',
|
||||
images: [
|
||||
{
|
||||
resourceId: 'resource-agent-stream',
|
||||
imageSrc: '/agent-stream.png',
|
||||
thumbnailSrc: null,
|
||||
width: 512,
|
||||
height: 512,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
options.onEvent?.({
|
||||
event: 'done',
|
||||
data: { conversationId, title: null },
|
||||
});
|
||||
},
|
||||
);
|
||||
loadEditorProjectMock.mockResolvedValueOnce({
|
||||
projectId: 'editor-project-default',
|
||||
title: '默认项目',
|
||||
@@ -1915,12 +1933,13 @@ describe('ImageCanvasEditorView', () => {
|
||||
'editor-agent-conv-test',
|
||||
);
|
||||
});
|
||||
fireEvent.change(await screen.findByLabelText('发送给画布 Agent'), {
|
||||
target: { value: '生成一张图' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: '发送' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '确认' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(confirmEditorAgentToolCallMock).toHaveBeenCalledWith(
|
||||
'editor-agent-conv-test',
|
||||
0,
|
||||
);
|
||||
expect(loadEditorProjectMock).toHaveBeenCalledWith(
|
||||
'editor-project-default',
|
||||
);
|
||||
|
||||
@@ -10,16 +10,15 @@ import {
|
||||
} from 'react';
|
||||
|
||||
import type { ExternalGenerationTaskRecord } from '../../../packages/shared/src/contracts/externalGeneration';
|
||||
import type { EditorAgentGenerationResultEvent } from '../../../packages/shared/src/contracts/editorAgent';
|
||||
import { loadFrontendRuntimeConfig } from '../../services/frontendRuntimeConfigService';
|
||||
import {
|
||||
createEditorAsset,
|
||||
createEditorProjectResource,
|
||||
type EditorAssetSnapshot,
|
||||
type EditorProjectSnapshot,
|
||||
loadEditorProject,
|
||||
loadEditorGenerationPricing,
|
||||
loadEditorProject,
|
||||
} from '../../services/image-editor/editorProjectClient';
|
||||
import { loadFrontendRuntimeConfig } from '../../services/frontendRuntimeConfigService';
|
||||
import { shouldShowRechargeEntry } from '../../services/payment/paymentPlatform';
|
||||
import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient';
|
||||
import { useAuthUi } from '../auth/AuthUiContext';
|
||||
@@ -78,11 +77,11 @@ import {
|
||||
} from './useImageCanvasAssetCanvasBridge';
|
||||
import { useImageCanvasAssetExportWorkflow } from './useImageCanvasAssetExportWorkflow';
|
||||
import { useImageCanvasAssetLibrary } from './useImageCanvasAssetLibrary';
|
||||
import { useImageCanvasContextStore } from './useImageCanvasContextStore.ts';
|
||||
import { useImageCanvasEditorChrome } from './useImageCanvasEditorChrome';
|
||||
import { useImageCanvasGenerationSurface } from './useImageCanvasGenerationSurface';
|
||||
import { useImageCanvasKeyboardShortcuts } from './useImageCanvasKeyboardShortcuts';
|
||||
import { useImageCanvasLayerCommands } from './useImageCanvasLayerCommands';
|
||||
import { useImageCanvasContextStore } from './useImageCanvasContextStore.ts';
|
||||
import { useImageCanvasProjectPersistence } from './useImageCanvasProjectPersistence';
|
||||
import { useImageCanvasStageController } from './useImageCanvasStageController';
|
||||
import { useImageCanvasStageInteractions } from './useImageCanvasStageInteractions';
|
||||
@@ -1096,20 +1095,14 @@ export function ImageCanvasEditorView({
|
||||
},
|
||||
[applyGeneratedProjectSnapshot, projectId, refreshEditorWalletBalance],
|
||||
);
|
||||
const handleEditorAgentGenerationResult = useCallback(
|
||||
(event: EditorAgentGenerationResultEvent) => {
|
||||
const hasGeneratedResource = event.images.some((image) =>
|
||||
image.resourceId?.trim(),
|
||||
);
|
||||
if (!projectId || !hasGeneratedResource) {
|
||||
return;
|
||||
}
|
||||
void loadEditorProject(projectId)
|
||||
.then(applyGeneratedProjectSnapshot)
|
||||
.catch(() => undefined);
|
||||
},
|
||||
[applyGeneratedProjectSnapshot, projectId],
|
||||
);
|
||||
const handleEditorAgentCanvasRefreshRequested = useCallback(() => {
|
||||
if (!projectId) {
|
||||
return;
|
||||
}
|
||||
void loadEditorProject(projectId)
|
||||
.then(applyGeneratedProjectSnapshot)
|
||||
.catch(() => undefined);
|
||||
}, [applyGeneratedProjectSnapshot, projectId]);
|
||||
const persistUpdatedLayerResource = useCallback(
|
||||
(layer: CanvasLayer) => {
|
||||
if (!projectId) {
|
||||
@@ -2078,7 +2071,8 @@ export function ImageCanvasEditorView({
|
||||
onActivateGenerationDialog: activateCanvasGenerationDialog,
|
||||
onFocusExternalTask: focusExternalGenerationTask,
|
||||
onExternalTasksCompleted: handleExternalGenerationTasksCompleted,
|
||||
onEditorAgentGenerationResult: handleEditorAgentGenerationResult,
|
||||
onEditorAgentCanvasRefreshRequested:
|
||||
handleEditorAgentCanvasRefreshRequested,
|
||||
onToggleTaskSidebar: toggleTaskSidebar,
|
||||
onToggleAgentConversation: toggleAgentConversation,
|
||||
onCropExpandHandlePointerDown: generationSurface.startCropExpandFrameResize,
|
||||
|
||||
@@ -7,9 +7,9 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
import type { ExternalGenerationTaskRecord } from '../../../packages/shared/src/contracts/externalGeneration';
|
||||
import type { EditorAgentGenerationResultEvent } from '../../../packages/shared/src/contracts/editorAgent';
|
||||
import { EditorAgentConversationPanelView } from '@/src/components/image-editor/EditorAgentConversation/EditorAgentConversationPanelView.tsx';
|
||||
|
||||
import type { ExternalGenerationTaskRecord } from '../../../packages/shared/src/contracts/externalGeneration';
|
||||
import { ImageCanvasBottomToolbarView } from './ImageCanvasBottomToolbarView';
|
||||
import { ImageCanvasContextMenusView } from './ImageCanvasContextMenusView';
|
||||
import type {
|
||||
@@ -126,9 +126,7 @@ export type ImageCanvasStageViewProps = {
|
||||
onActivateGenerationDialog: (dialog: CanvasGenerationDialogState) => void;
|
||||
onFocusExternalTask: (task: ExternalGenerationTaskRecord) => void;
|
||||
onExternalTasksCompleted?: (tasks: ExternalGenerationTaskRecord[]) => void;
|
||||
onEditorAgentGenerationResult?: (
|
||||
event: EditorAgentGenerationResultEvent,
|
||||
) => void;
|
||||
onEditorAgentCanvasRefreshRequested?: () => void;
|
||||
onToggleTaskSidebar: () => void;
|
||||
onToggleAgentConversation: () => void;
|
||||
onCropExpandHandlePointerDown: (
|
||||
@@ -259,7 +257,7 @@ export function ImageCanvasStageView({
|
||||
onActivateGenerationDialog,
|
||||
onFocusExternalTask,
|
||||
onExternalTasksCompleted,
|
||||
onEditorAgentGenerationResult,
|
||||
onEditorAgentCanvasRefreshRequested,
|
||||
onToggleTaskSidebar,
|
||||
onToggleAgentConversation,
|
||||
onCropExpandHandlePointerDown,
|
||||
@@ -476,7 +474,7 @@ export function ImageCanvasStageView({
|
||||
onToggleOpen={onToggleAgentConversation}
|
||||
layers={layers}
|
||||
assets={editorAgentAssets}
|
||||
onGenerationResult={onEditorAgentGenerationResult}
|
||||
onCanvasRefreshRequested={onEditorAgentCanvasRefreshRequested}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user