feat: use acp for desktop chat prompt (feature toggle off) (#9802)
Signed-off-by: Douwe M Osinga <douwe@sidewalklabs.com> Co-authored-by: Douwe M Osinga <douwe@sidewalklabs.com>
This commit is contained in:
@@ -16,7 +16,7 @@ import { ChatType } from '../types/chat';
|
||||
import { useIsMobile } from '../hooks/use-mobile';
|
||||
import { useNavigationContextSafe } from './Layout/NavigationContext';
|
||||
import { cn } from '../utils';
|
||||
import { useChatStream } from '../hooks/useChatStream';
|
||||
import { useChatSession } from '../hooks/useChatSession';
|
||||
import { useNavigation } from '../hooks/useNavigation';
|
||||
import { RecipeHeader } from './RecipeHeader';
|
||||
import { RecipeWarningModal } from './ui/RecipeWarningModal';
|
||||
@@ -114,7 +114,7 @@ export default function BaseChat({
|
||||
tokenState,
|
||||
notifications: toolCallNotifications,
|
||||
onMessageUpdate,
|
||||
} = useChatStream({
|
||||
} = useChatSession({
|
||||
sessionId,
|
||||
onStreamFinish,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { render, type RenderOptions, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { confirmToolAction } from '../api';
|
||||
import { resolveAcpPermissionRequest } from '../acp/permissionRequests';
|
||||
import { IntlTestWrapper } from '../i18n/test-utils';
|
||||
import ToolApprovalButtons from './ToolApprovalButtons';
|
||||
|
||||
vi.mock('../api', () => ({
|
||||
confirmToolAction: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../acp/permissionRequests', () => ({
|
||||
resolveAcpPermissionRequest: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../acpChatFeatureFlag', () => ({
|
||||
USE_ACP_CHAT: true,
|
||||
}));
|
||||
|
||||
const renderWithIntl = (ui: React.ReactElement, options?: RenderOptions) =>
|
||||
render(ui, { wrapper: IntlTestWrapper, ...options });
|
||||
|
||||
const confirmToolActionMock = vi.mocked(confirmToolAction);
|
||||
const resolveAcpPermissionRequestMock = vi.mocked(resolveAcpPermissionRequest);
|
||||
|
||||
describe('ToolApprovalButtons', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('marks the approval accepted when the ACP request resolves', async () => {
|
||||
resolveAcpPermissionRequestMock.mockReturnValueOnce(true);
|
||||
|
||||
renderWithIntl(
|
||||
<ToolApprovalButtons
|
||||
data={{
|
||||
id: 'tool-call-approved',
|
||||
toolName: 'developer__shell',
|
||||
sessionId: 'session-1',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Allow Once' }));
|
||||
|
||||
expect(resolveAcpPermissionRequestMock).toHaveBeenCalledWith(
|
||||
'session-1',
|
||||
'tool-call-approved',
|
||||
'allow_once'
|
||||
);
|
||||
expect(confirmToolActionMock).not.toHaveBeenCalled();
|
||||
expect(screen.getByText('developer__shell - Allowed once')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('falls back to the REST confirmation when no ACP request is pending', async () => {
|
||||
resolveAcpPermissionRequestMock.mockReturnValueOnce(false);
|
||||
confirmToolActionMock.mockResolvedValueOnce({ error: undefined } as Awaited<
|
||||
ReturnType<typeof confirmToolAction>
|
||||
>);
|
||||
|
||||
renderWithIntl(
|
||||
<ToolApprovalButtons
|
||||
data={{
|
||||
id: 'tool-call-rerun',
|
||||
toolName: 'developer__shell',
|
||||
sessionId: 'session-1',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Allow Once' }));
|
||||
|
||||
expect(resolveAcpPermissionRequestMock).toHaveBeenCalledWith(
|
||||
'session-1',
|
||||
'tool-call-rerun',
|
||||
'allow_once'
|
||||
);
|
||||
expect(confirmToolActionMock).toHaveBeenCalledWith({
|
||||
body: {
|
||||
sessionId: 'session-1',
|
||||
id: 'tool-call-rerun',
|
||||
action: 'allow_once',
|
||||
principalType: 'Tool',
|
||||
},
|
||||
});
|
||||
expect(screen.getByText('developer__shell - Allowed once')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button } from './ui/button';
|
||||
import { confirmToolAction, Permission } from '../api';
|
||||
import { resolveAcpPermissionRequest } from '../acp/permissionRequests';
|
||||
import { USE_ACP_CHAT } from '../acpChatFeatureFlag';
|
||||
import { defineMessages, useIntl } from '../i18n';
|
||||
|
||||
const i18n = defineMessages({
|
||||
@@ -75,10 +77,18 @@ export default function ToolApprovalButtons({ data }: { data: ToolApprovalData }
|
||||
}, [id, decision, isClicked]);
|
||||
|
||||
const handleAction = async (action: Permission) => {
|
||||
setDecision(action);
|
||||
setIsClicked(true);
|
||||
|
||||
try {
|
||||
// Edit-in-place reruns go through the legacy REST path even when ACP chat is
|
||||
// enabled, so fall back to confirmToolAction when no ACP request is pending.
|
||||
if (USE_ACP_CHAT && resolveAcpPermissionRequest(sessionId, id, action)) {
|
||||
setDecision(action);
|
||||
setIsClicked(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setDecision(action);
|
||||
setIsClicked(true);
|
||||
|
||||
const response = await confirmToolAction({
|
||||
body: {
|
||||
sessionId,
|
||||
|
||||
Reference in New Issue
Block a user