fix: show tool inputs before approval (#10932)
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { IntlTestWrapper } from '../i18n/test-utils';
|
||||
import type { ActionRequired } from '../types/message';
|
||||
import ToolCallConfirmation from './ToolCallConfirmation';
|
||||
|
||||
vi.mock('./ToolApprovalButtons', () => ({
|
||||
default: () => <div data-testid="approval-buttons" />,
|
||||
}));
|
||||
|
||||
const securityPrompt = 'This command sends a local file to a remote service.';
|
||||
|
||||
const actionRequiredContent = {
|
||||
type: 'actionRequired',
|
||||
data: {
|
||||
actionType: 'toolConfirmation',
|
||||
id: 'request-1',
|
||||
toolName: 'developer__shell',
|
||||
arguments: {
|
||||
command: 'upload /home/alice/private.txt to files.example.test',
|
||||
},
|
||||
prompt: securityPrompt,
|
||||
},
|
||||
} as ActionRequired & { type: 'actionRequired' };
|
||||
|
||||
describe('ToolCallConfirmation', () => {
|
||||
it('shows the concrete tool arguments before approval', () => {
|
||||
render(
|
||||
<ToolCallConfirmation
|
||||
sessionId="session-1"
|
||||
isClicked={false}
|
||||
actionRequiredContent={actionRequiredContent}
|
||||
/>,
|
||||
{ wrapper: IntlTestWrapper }
|
||||
);
|
||||
|
||||
expect(screen.getByText('command')).toBeInTheDocument();
|
||||
expect(screen.getByText(/upload \/home\/alice\/private\.txt/)).toBeInTheDocument();
|
||||
expect(screen.getByTestId('approval-buttons')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the security prompt before approval', () => {
|
||||
render(
|
||||
<ToolCallConfirmation
|
||||
sessionId="session-1"
|
||||
isClicked={false}
|
||||
actionRequiredContent={actionRequiredContent}
|
||||
/>,
|
||||
{ wrapper: IntlTestWrapper }
|
||||
);
|
||||
|
||||
expect(screen.getByText(securityPrompt)).toBeInTheDocument();
|
||||
expect(screen.getByTestId('approval-buttons')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import type { ActionRequired } from '../types/message';
|
||||
import { defineMessages, useIntl } from '../i18n';
|
||||
import { snakeToTitleCase } from '../utils';
|
||||
import ToolApprovalButtons from './ToolApprovalButtons';
|
||||
import { ToolCallArguments, type ToolCallArgumentValue } from './ToolCallArguments';
|
||||
|
||||
const i18n = defineMessages({
|
||||
allowToolCallWithName: {
|
||||
@@ -35,7 +36,7 @@ export default function ToolConfirmation({
|
||||
}: ToolConfirmationProps) {
|
||||
const intl = useIntl();
|
||||
const data = actionRequiredContent.data as ToolConfirmationData;
|
||||
const { id, toolName, prompt } = data;
|
||||
const { id, toolName, arguments: toolArguments, prompt } = data;
|
||||
const displayName = formatToolName(toolName);
|
||||
|
||||
return (
|
||||
@@ -45,9 +46,13 @@ export default function ToolConfirmation({
|
||||
? intl.formatMessage(i18n.allowToolCallWithName, { toolName: displayName })
|
||||
: intl.formatMessage(i18n.gooseWouldLikeToCallWithName, { toolName: displayName })}
|
||||
</div>
|
||||
<ToolApprovalButtons
|
||||
data={{ id, toolName, prompt: prompt ?? undefined, sessionId, isClicked }}
|
||||
/>
|
||||
<div className="px-4 pb-2">
|
||||
{prompt && <div className="py-2 text-sm text-amber-600 dark:text-amber-400">{prompt}</div>}
|
||||
<ToolCallArguments args={toolArguments as Record<string, ToolCallArgumentValue>} />
|
||||
<ToolApprovalButtons
|
||||
data={{ id, toolName, prompt: prompt ?? undefined, sessionId, isClicked }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user