Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions frontend/src/components/chat/GeneratedImages.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ describe('GeneratedImages', () => {
const card = screen.getByTestId('generated-image-pending');
expect(card).toHaveStyle({ width: `${imageDisplayWidth(2, 3)}px` });
expect(screen.getByRole('status')).toHaveTextContent('正在生成图片');
expect(screen.getByText('正在生成图片')).toHaveClass('sr-only');
expect(screen.getByText('12 秒')).toBeInTheDocument();

act(() => {
Expand Down Expand Up @@ -179,4 +180,17 @@ describe('collectPendingImageGenerations', () => {
]);
expect(collectPendingImageGenerations(null, [])).toEqual([]);
});

it('drops a failed card once a later generation replaces it', () => {
const failed = { status: 'failed' as const, resultSummary: { kind: 'generated_image', truncated: false, error_code: 'no_image_returned' } as never };
const retrying = runWith([call(failed), call({ toolCallId: 'call-2' })]);
expect(collectPendingImageGenerations(retrying, [])).toMatchObject([{ toolCallId: 'call-2', status: 'running' }]);

const retried = runWith([call(failed), call({
toolCallId: 'call-2',
status: 'success',
resultSummary: { kind: 'generated_image', truncated: false, file_id: 'file-1' } as never,
})]);
expect(collectPendingImageGenerations(retried, [block])).toEqual([]);
});
});
2 changes: 1 addition & 1 deletion frontend/src/components/chat/GeneratedImages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function PendingImageCard({ pending }: { pending: PendingImageGeneration }) {
<ImageGenerationDots elapsedSeconds={elapsedSeconds} active={running} />
<span
className={running
? 'absolute left-3 top-2.5 text-xs font-medium text-muted-foreground'
? 'sr-only'
: 'absolute inset-x-3 top-1/2 -translate-y-1/2 text-center text-sm text-muted-foreground'}
>
{label}
Expand Down
53 changes: 27 additions & 26 deletions frontend/src/components/chat/generatedImageModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,34 @@ export function collectPendingImageGenerations(
): PendingImageGeneration[] {
if (!run) return [];
const renderedFileIds = new Set(blocks.map(block => block.file_id));
const calls = run.steps.flatMap(step => step.toolCalls.filter(call => call.toolName === GENERATE_IMAGE_TOOL_NAME));
const pending: PendingImageGeneration[] = [];
for (const step of run.steps) {
for (const call of step.toolCalls) {
if (call.toolName !== GENERATE_IMAGE_TOOL_NAME) continue;
const summary = call.resultSummary as (Record<string, unknown> | undefined);
const fileId = typeof summary?.file_id === 'string' ? summary.file_id : null;
let status: PendingImageStatus;
if (call.status === 'running') {
status = 'running';
} else if (call.status === 'success') {
if (!fileId || renderedFileIds.has(fileId)) continue;
status = 'running';
} else if (call.status === 'interrupted') {
status = 'interrupted';
} else {
status = 'failed';
}
const aspectRatio = typeof call.arguments?.aspect_ratio === 'string' ? call.arguments.aspect_ratio : '1:1';
pending.push({
toolCallId: call.toolCallId,
status,
aspectRatio,
startedAt: call.startedAt,
completedAt: call.completedAt,
errorCode: typeof summary?.error_code === 'string' ? summary.error_code : null,
});
calls.forEach((call, index) => {
const summary = call.resultSummary as (Record<string, unknown> | undefined);
const fileId = typeof summary?.file_id === 'string' ? summary.file_id : null;
let status: PendingImageStatus;
if (call.status === 'running') {
status = 'running';
} else if (call.status === 'success') {
if (!fileId || renderedFileIds.has(fileId)) return;
status = 'running';
} else if (index < calls.length - 1) {
// 失败或中断后又发起了生图(重试),由后一张卡片接替,不再保留失败卡片。
return;
} else if (call.status === 'interrupted') {
status = 'interrupted';
} else {
status = 'failed';
}
}
const aspectRatio = typeof call.arguments?.aspect_ratio === 'string' ? call.arguments.aspect_ratio : '1:1';
pending.push({
toolCallId: call.toolCallId,
status,
aspectRatio,
startedAt: call.startedAt,
completedAt: call.completedAt,
errorCode: typeof summary?.error_code === 'string' ? summary.error_code : null,
});
});
return pending;
}
Loading