Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8f7f2f6
feat(ai-native): maintain bounded ACP standby capacity
lulusir Jul 24, 2026
998c561
fix(ai-native): improve ACP error guidance
lulusir Jul 27, 2026
aefb258
feat(ai-native): localize Agent Task project guidance
lulusir Jul 27, 2026
7b09e9a
test(ai-native): cover actionable ACP error guidance
lulusir Jul 29, 2026
33de719
fix(ai-native): stabilize ACP task lifecycle and e2e
lulusir Jul 30, 2026
4a89aaa
feat(ai-native): optimize agentic task conversation switching
lulusir Jul 31, 2026
2f10cca
fix(ai-native): sync virtual list dependency lockfile
lulusir Aug 3, 2026
c2c2835
fix(ai-native): stabilize agentic virtual list e2e assertions
lulusir Aug 3, 2026
83b55d5
fix(ai-native): stabilize agentic virtual list interactions
lulusir Aug 3, 2026
6af7054
fix(ai-native): stabilize virtualized session restore e2e
lulusir Aug 5, 2026
22b13b7
fix(ai-native): keep restored agentic session active
lulusir Aug 5, 2026
a003f33
fix(ai-native): stabilize agentic chat e2e virtualization
lulusir Aug 6, 2026
bfb4dca
fix(ai-native): preserve virtualized agentic history rows
lulusir Aug 6, 2026
b68b95d
test(ai-native): stabilize virtualized recovery e2e
lulusir Aug 6, 2026
6ea1690
fix(ai-native): preserve active task session on reload
lulusir Aug 11, 2026
92bf01a
fix(ai-native): clarify ACP session restoration
lulusir Aug 11, 2026
0271341
fix(ai-native): restore ACP slash command catalogs
lulusir Aug 12, 2026
ccd6c4b
fix(ai-native): sync agent task status after cancel
lulusir Aug 18, 2026
c0e0903
feat(ai-native): restore agent-owned ACP sessions
lulusir Aug 20, 2026
22119a7
feat(ai-native): use agent-owned session browser
lulusir Aug 20, 2026
8563c64
test(playwright): isolate temporary workspaces
lulusir Aug 20, 2026
e5d5604
fix(ai-native): align agent session creation and labels
lulusir Aug 21, 2026
f72da1d
feat(ai-native): complete agent-owned session workflow
lulusir Aug 21, 2026
ff1eef9
feat(ai-native): default agent layout to split workbench
lulusir Aug 21, 2026
4f15f24
fix(ai-native): simplify initial task loading state
lulusir Aug 25, 2026
a4781a9
fix(ai-native): stabilize agent session e2e setup
lulusir Aug 25, 2026
0ebb192
fix(ai-native): preserve ACP request session context
lulusir Aug 31, 2026
503c43e
fix(ai-native): preserve ACP restored user turns
lulusir Sep 1, 2026
02fee04
test(playwright): align agentic session e2e coverage
lulusir Sep 1, 2026
66d90aa
fix(ai-native): restore submitted ACP user turns
lulusir Sep 1, 2026
dea9518
fix(ai-native): hide internal ACP prompt metadata
lulusir Sep 1, 2026
dd6615e
test(playwright): wait for ACP prompt acceptance
lulusir Sep 1, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

.package-temp-dir
.tmp/
/tools/playwright/tmp/

# Logs
logs
Expand Down
96 changes: 54 additions & 42 deletions packages/ai-native/CONTEXT.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,64 @@ describe('AcpChatMentionInput ref contract', () => {
});
});

it('clears an accepted first-task draft after it is promoted to an active session', async () => {
mockUseActualMentionInput = true;
jest.requireMock('@opensumi/ide-core-browser').useInjectable.mockReturnValue(createMockService());
const ref = React.createRef<AcpTurnEditorHandle>();
const submission = deferred<TurnActionResult>();
const submit = jest.fn(() => submission.promise);
const onDraftChange = jest.fn();
let promoteSession!: (sessionId: string) => void;

const Harness = () => {
const [activeSessionId, setActiveSessionId] = React.useState<string>();
promoteSession = setActiveSessionId;
return React.createElement(AcpTurnEditor, {
ref,
variant: 'main',
activeSessionId,
initialDraft: { message: 'first task draft' },
onDraftChange,
onSend: jest.fn(),
setTheme: jest.fn(),
agentId: '',
setAgentId: jest.fn(),
command: '',
setCommand: jest.fn(),
turnActions: {
submit,
stop: jest.fn(),
fastTrack: jest.fn(),
invalidateFastTrack: jest.fn(),
takeBackLastQueuedTurn: jest.fn(),
},
});
};

act(() => {
render(React.createElement(Harness), container);
});

const editor = container.querySelector('[contenteditable="true"]') as HTMLDivElement;
act(() => {
dispatchEditorKey(editor, { key: 'Enter' });
promoteSession('promoted-session');
});

await act(async () => {
submission.resolve({ accepted: true, outcome: 'started' });
await submission.promise;
await Promise.resolve();
});

expect(submit).toHaveBeenCalledWith(
{ message: 'first task draft', images: [], agentId: '', command: '' },
'normal',
);
expect(ref.current!.getDraft()).toEqual({ message: '', images: [], agentId: '', command: '' });
expect(onDraftChange).toHaveBeenLastCalledWith({ message: '', images: [], agentId: '', command: '' });
});

it('preserves text, pasted attachment, agent, and command changes made while submission is pending', async () => {
mockUseActualMentionInput = true;
const upload = jest.fn(async () => 'data:image/png;base64,new');
Expand Down
178 changes: 144 additions & 34 deletions packages/ai-native/__test__/browser/acp-chat-view-header.test.tsx

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions packages/ai-native/__test__/browser/acp-queued-turns.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const baseSnapshot: AcpQueuedTurnSnapshot = {
entries: [{ id: 'turn-1', message: 'first' }],
canResume: false,
canFastTrack: false,
initialStartPending: false,
};

const query = (selector: string) => container.querySelector(selector);
Expand Down Expand Up @@ -64,6 +65,7 @@ function renderQueue(
onDelete?: jest.Mock;
onImmediateSend?: jest.Mock;
onEditorReady?: jest.Mock;
onOpenCapacitySettings?: jest.Mock;
} = {},
) {
const snapshot = { ...baseSnapshot, ...overrides };
Expand Down Expand Up @@ -97,12 +99,24 @@ function renderQueue(
onDelete={handlers.onDelete}
onImmediateSend={handlers.onImmediateSend}
onEditorReady={handlers.onEditorReady}
onOpenCapacitySettings={overrides.onOpenCapacitySettings}
/>,
);
});
return handlers;
}

it('shows a loading status while the first Task is launching', () => {
renderQueue({
activeSessionId: undefined,
entries: [],
initialStartPending: true,
});

expect(query('[data-testid="acp-task-launch-status"]')?.textContent).toContain('Starting task');
expect(query('[data-testid="acp-task-launch-status"] button')).toBeNull();
});

it('renders paused state and resumes', () => {
renderQueue({ phase: 'paused', pauseReason: 'manual-stop', canResume: true });
expect(query('[data-testid="acp-queued-turn-status"]')?.textContent).toContain('Paused');
Expand All @@ -111,6 +125,31 @@ it('renders paused state and resumes', () => {
expect(onResume).toHaveBeenCalledTimes(1);
});

it('renders capacity exhaustion as a persistent actionable alert', () => {
const onOpenCapacitySettings = jest.fn();
renderQueue({
phase: 'paused',
pauseReason: 'start-failed',
pauseError: {
name: 'ACP_THREAD_POOL_SATURATED',
message: 'ACP concurrent tasks have reached the configured limit of 2.',
limit: 2,
},
canResume: true,
onOpenCapacitySettings,
});

expect(query('[data-testid="acp-capacity-error"]')?.getAttribute('role')).toBe('alert');
expect(query('[data-testid="acp-capacity-error"]')?.textContent).toContain('capacity limit (2) has been reached');
expect(query('[data-testid="acp-capacity-error"]')?.textContent).toContain(
'Your task draft and unsent content have been preserved',
);
click('[data-testid="acp-capacity-retry"]');
click('[data-testid="acp-capacity-open-settings"]');
expect(onResume).toHaveBeenCalledTimes(1);
expect(onOpenCapacitySettings).toHaveBeenCalledTimes(1);
});

it.each([
[0, '0 Queued Turns'],
[1, '1 Queued Turn'],
Expand Down
Loading
Loading