fix(pi): converge worker failures and thinking state

This commit is contained in:
2026-08-25 11:45:14 +08:00
parent 274187e3cf
commit 61817b161f
28 changed files with 2019 additions and 118 deletions

View File

@@ -1,4 +1,4 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import type { ProviderAccount, ProviderVendorInfo } from '@/lib/providers';
@@ -102,6 +102,41 @@ describe('PI-130 feature-complete Coding UI', () => {
expect(onSubmit).toHaveBeenCalledOnce();
});
it('unlocks editing and offers recovery after the local Agent exits', async () => {
const onRecover = vi.fn();
const { CodingComposer } = await import('@/pages/Chat/CodingComposer');
render(
<CodingComposer
value="Draft remains editable"
editable
canSend={false}
preparing={false}
recovering={false}
runStatus="error"
mode="prompt"
queue={{ items: [] }}
error="本地 Agent 已中断,原请求未自动重发。"
recoverableError
acceptedCount={0}
attachments={[]}
submitting={false}
placeholder="Prompt"
onChange={vi.fn()}
onModeChange={vi.fn()}
onSubmit={vi.fn()}
onRecover={onRecover}
onAddFiles={vi.fn()}
onRemoveAttachment={vi.fn()}
/>,
);
expect(screen.getByRole('textbox')).toBeEnabled();
expect(screen.getByRole('alert')).toHaveTextContent('本地 Agent 已中断,原请求未自动重发。');
expect(screen.queryByText('当前对话正在处理。')).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '重试' }));
expect(onRecover).toHaveBeenCalledOnce();
});
it('answers product interactions and explains stale responses', async () => {
interactionApi.respond.mockResolvedValueOnce(undefined).mockRejectedValueOnce(new Error('409 stale'));
const { CodingInteractionPanel } = await import('@/pages/Chat/CodingInteractionPanel');
@@ -198,8 +233,9 @@ describe('PI-130 feature-complete Coding UI', () => {
agentId: 'agent-1',
title: 'Feature UI',
model: {
model: { accountId: 'account-1', modelId: 'model-a', thinkingLevel: 'medium' },
model: { accountId: 'account-1', modelId: 'model-a', thinkingLevel: 'high' },
modelResolution: 'resolved',
availableThinkingLevels: ['high'],
},
},
nodes: [],
@@ -227,9 +263,13 @@ describe('PI-130 feature-complete Coding UI', () => {
await waitFor(() => expect(interactionApi.model).toHaveBeenCalledWith('conversation-1', {
accountId: 'account-1',
modelId: 'model-b',
thinkingLevel: 'medium',
thinkingLevel: 'high',
}));
await waitFor(() => expect(callbacks.refresh).toHaveBeenCalledOnce());
const thinkingSelect = screen.getByRole('combobox', { name: '当前对话思考级别' });
expect(within(thinkingSelect).getAllByRole('option')).toHaveLength(1);
expect(within(thinkingSelect).getByRole('option', { name: '高思考' })).toBeInTheDocument();
expect(within(thinkingSelect).queryByRole('option', { name: '关闭思考' })).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '中止' }));
await waitFor(() => expect(interactionApi.abort).toHaveBeenCalledWith('conversation-1'));
fireEvent.click(screen.getByRole('button', { name: '创建分支' }));