@patternfly/chatbot 6.4.0-prerelease.21 → 6.4.0-prerelease.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/cjs/Message/Message.d.ts +3 -0
  2. package/dist/cjs/Message/Message.js +3 -2
  3. package/dist/cjs/ToolCall/ToolCall.d.ts +44 -0
  4. package/dist/cjs/ToolCall/ToolCall.js +14 -0
  5. package/dist/cjs/ToolCall/ToolCall.test.d.ts +1 -0
  6. package/dist/cjs/ToolCall/ToolCall.test.js +144 -0
  7. package/dist/cjs/ToolCall/index.d.ts +2 -0
  8. package/dist/cjs/ToolCall/index.js +23 -0
  9. package/dist/cjs/index.d.ts +2 -0
  10. package/dist/cjs/index.js +4 -1
  11. package/dist/css/main.css +29 -0
  12. package/dist/css/main.css.map +1 -1
  13. package/dist/dynamic/ToolCall/package.json +1 -0
  14. package/dist/esm/Message/Message.d.ts +3 -0
  15. package/dist/esm/Message/Message.js +3 -2
  16. package/dist/esm/ToolCall/ToolCall.d.ts +44 -0
  17. package/dist/esm/ToolCall/ToolCall.js +10 -0
  18. package/dist/esm/ToolCall/ToolCall.test.d.ts +1 -0
  19. package/dist/esm/ToolCall/ToolCall.test.js +139 -0
  20. package/dist/esm/ToolCall/index.d.ts +2 -0
  21. package/dist/esm/ToolCall/index.js +2 -0
  22. package/dist/esm/index.d.ts +2 -0
  23. package/dist/esm/index.js +2 -0
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +1 -1
  26. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolCall.tsx +45 -0
  27. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +10 -0
  28. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +1 -1
  29. package/src/Message/Message.tsx +5 -0
  30. package/src/ToolCall/ToolCall.scss +37 -0
  31. package/src/ToolCall/ToolCall.test.tsx +184 -0
  32. package/src/ToolCall/ToolCall.tsx +147 -0
  33. package/src/ToolCall/index.ts +3 -0
  34. package/src/index.ts +3 -0
  35. package/src/main.scss +1 -0
@@ -0,0 +1,139 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { render, screen } from '@testing-library/react';
12
+ import userEvent from '@testing-library/user-event';
13
+ import '@testing-library/jest-dom';
14
+ import ToolCall from './ToolCall';
15
+ describe('ToolCall', () => {
16
+ const defaultProps = {
17
+ titleText: 'ToolCall Title',
18
+ loadingText: 'Loading ToolCall'
19
+ };
20
+ it('Renders with passed in titleText', () => {
21
+ render(_jsx(ToolCall, Object.assign({}, defaultProps)));
22
+ expect(screen.getByText(defaultProps.titleText)).toBeVisible();
23
+ });
24
+ it('Does not render with passed in loadingText when isLoading is false', () => {
25
+ render(_jsx(ToolCall, Object.assign({}, defaultProps)));
26
+ expect(screen.queryByText(defaultProps.loadingText)).not.toBeInTheDocument();
27
+ });
28
+ it('Renders with passed in loadingText when isLoading is true', () => {
29
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { isLoading: true })));
30
+ expect(screen.getByText(defaultProps.loadingText)).toBeVisible();
31
+ });
32
+ it('Does not render titleText when isLoading is true', () => {
33
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { isLoading: true })));
34
+ expect(screen.queryByText(defaultProps.titleText)).not.toBeInTheDocument();
35
+ });
36
+ it('Passes spinnerProps to Spinner', () => {
37
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { isLoading: true, spinnerProps: { id: 'spinner-test-id' } })));
38
+ expect(screen.getByRole('progressbar')).toHaveAttribute('id', 'spinner-test-id');
39
+ });
40
+ it('Does not render expandable toggle by default', () => {
41
+ render(_jsx(ToolCall, Object.assign({}, defaultProps)));
42
+ expect(screen.queryByRole('button', { name: defaultProps.titleText })).not.toBeInTheDocument();
43
+ });
44
+ it('Renders titleText inside expandable toggle when expandableContent is passed', () => {
45
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: "Expandable Content" })));
46
+ expect(screen.getByRole('button', { name: defaultProps.titleText })).toBeVisible();
47
+ });
48
+ it('Does not render expandable content when expandableContent is passed by default', () => {
49
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: "Expandable Content" })));
50
+ expect(screen.queryByText('Expandable Content')).not.toBeVisible();
51
+ });
52
+ it('Renders expandable content when expandableContent is passed and toggle is clicked', () => __awaiter(void 0, void 0, void 0, function* () {
53
+ const user = userEvent.setup();
54
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: "Expandable Content" })));
55
+ yield user.click(screen.getByRole('button', { name: defaultProps.titleText }));
56
+ expect(screen.getByText('Expandable Content')).toBeVisible();
57
+ }));
58
+ it('Passes expandableSectionProps to ExpandableSection', () => {
59
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: "Expandable Content", expandableSectionProps: { id: 'expandable-section-test-id', isExpanded: true } })));
60
+ expect(screen.getByRole('region').parentElement).toHaveAttribute('id', 'expandable-section-test-id');
61
+ });
62
+ it('Renders "run" action button by default', () => {
63
+ render(_jsx(ToolCall, Object.assign({}, defaultProps)));
64
+ expect(screen.getByRole('button', { name: 'Run tool' })).toBeVisible();
65
+ });
66
+ it('Renders "cancel" action button by default', () => {
67
+ render(_jsx(ToolCall, Object.assign({}, defaultProps)));
68
+ expect(screen.getByRole('button', { name: 'Cancel' })).toBeVisible();
69
+ });
70
+ it('Does not render "run" action button when isLoading is true', () => {
71
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { isLoading: true })));
72
+ expect(screen.queryByRole('button', { name: 'Run tool' })).not.toBeInTheDocument();
73
+ });
74
+ it('Does not render "cancel" action button when isLoading is true', () => {
75
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { isLoading: true })));
76
+ expect(screen.queryByRole('button', { name: 'Cancel' })).not.toBeInTheDocument();
77
+ });
78
+ it('Renders runButtonText when passed', () => {
79
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { runButtonText: "Run my custom tool" })));
80
+ expect(screen.getByRole('button', { name: 'Run my custom tool' })).toBeVisible();
81
+ });
82
+ it('Renders cancelButtonText when passed', () => {
83
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { cancelButtonText: "Cancel my custom tool" })));
84
+ expect(screen.getByRole('button', { name: 'Cancel my custom tool' })).toBeVisible();
85
+ });
86
+ it('Passes runButtonProps to Button', () => {
87
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { runButtonProps: { id: 'run-button-test-id' } })));
88
+ expect(screen.getByRole('button', { name: 'Run tool' })).toHaveAttribute('id', 'run-button-test-id');
89
+ });
90
+ it('Passes cancelButtonProps to Button', () => {
91
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { cancelButtonProps: { id: 'cancel-button-test-id' } })));
92
+ expect(screen.getByRole('button', { name: 'Cancel' })).toHaveAttribute('id', 'cancel-button-test-id');
93
+ });
94
+ it('Passes runActionItemProps to ActionListItem', () => {
95
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { runActionItemProps: { id: 'run-action-item-test-id' } })));
96
+ expect(screen.getByRole('button', { name: 'Run tool' }).parentElement).toHaveAttribute('id', 'run-action-item-test-id');
97
+ });
98
+ it('Passes cancelActionItemProps to ActionListItem', () => {
99
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { cancelActionItemProps: { id: 'cancel-action-item-test-id' } })));
100
+ expect(screen.getByRole('button', { name: 'Cancel' }).parentElement).toHaveAttribute('id', 'cancel-action-item-test-id');
101
+ });
102
+ it('Passes actionListProps to ActionList', () => {
103
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { actionListProps: { id: 'action-list-test-id' } })));
104
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#action-list-test-id')).toBeVisible();
105
+ });
106
+ it('Passes actionListGroupProps to ActionListGroup', () => {
107
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { actionListGroupProps: { id: 'action-list-group-test-id' } })));
108
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#action-list-group-test-id')).toBeVisible();
109
+ });
110
+ it('Passes actionListItemProps to ActionListItem for default actions', () => {
111
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { actionListItemProps: { className: 'action-list-item-test-class' } })));
112
+ expect(screen.getByRole('button', { name: 'Run tool' }).parentElement).toHaveClass('action-list-item-test-class');
113
+ expect(screen.getByRole('button', { name: 'Cancel' }).parentElement).toHaveClass('action-list-item-test-class');
114
+ });
115
+ it('Renders custom actions instead of default actions when actions are passed', () => {
116
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { actions: [_jsx("div", { children: "Custom action 1" }, "custom-action-1"), _jsx("div", { children: "Custom action 2" }, "custom-action-2")] })));
117
+ expect(screen.getByText('Custom action 1')).toBeVisible();
118
+ expect(screen.getByText('Custom action 2')).toBeVisible();
119
+ expect(screen.queryByRole('button', { name: 'Run tool' })).not.toBeInTheDocument();
120
+ expect(screen.queryByRole('button', { name: 'Cancel' })).not.toBeInTheDocument();
121
+ });
122
+ it('Passes actionListItemProps to ActionListItem for custom actions', () => {
123
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { actions: [_jsx("div", { children: "Custom action 1" }, "custom-action-1"), _jsx("div", { children: "Custom action 2" }, "custom-action-2")], actionListItemProps: { className: 'action-list-item-test-class' } })));
124
+ expect(screen.getByText('Custom action 1').parentElement).toHaveClass('action-list-item-test-class');
125
+ expect(screen.getByText('Custom action 2').parentElement).toHaveClass('action-list-item-test-class');
126
+ });
127
+ it('Passes cardProps to Card', () => {
128
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { cardProps: { id: 'card-test-id' } })));
129
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#card-test-id')).toBeVisible();
130
+ });
131
+ it('Passes cardBodyProps to CardBody', () => {
132
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { cardBodyProps: { id: 'card-body-test-id' } })));
133
+ expect(screen.getByText(defaultProps.titleText).closest('#card-body-test-id')).toBeVisible();
134
+ });
135
+ it('Passes cardFooterProps to CardFooter', () => {
136
+ render(_jsx(ToolCall, Object.assign({}, defaultProps, { cardFooterProps: { id: 'card-footer-test-id' } })));
137
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#card-footer-test-id')).toBeVisible();
138
+ });
139
+ });
@@ -0,0 +1,2 @@
1
+ export { default } from './ToolCall';
2
+ export * from './ToolCall';
@@ -0,0 +1,2 @@
1
+ export { default } from './ToolCall';
2
+ export * from './ToolCall';
@@ -60,6 +60,8 @@ export { default as SourcesCard } from './SourcesCard';
60
60
  export * from './SourcesCard';
61
61
  export { default as TermsOfUse } from './TermsOfUse';
62
62
  export * from './TermsOfUse';
63
+ export { default as ToolCall } from './ToolCall';
64
+ export * from './ToolCall';
63
65
  export { default as ToolResponse } from './ToolResponse';
64
66
  export * from './ToolResponse';
65
67
  export { default as tracking } from './tracking';
package/dist/esm/index.js CHANGED
@@ -61,6 +61,8 @@ export { default as SourcesCard } from './SourcesCard';
61
61
  export * from './SourcesCard';
62
62
  export { default as TermsOfUse } from './TermsOfUse';
63
63
  export * from './TermsOfUse';
64
+ export { default as ToolCall } from './ToolCall';
65
+ export * from './ToolCall';
64
66
  export { default as ToolResponse } from './ToolResponse';
65
67
  export * from './ToolResponse';
66
68
  export { default as tracking } from './tracking';
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
1
+ {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolCall/ToolCall.test.tsx","../src/ToolCall/ToolCall.tsx","../src/ToolCall/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.4.0-prerelease.21",
3
+ "version": "6.4.0-prerelease.22",
4
4
  "description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -0,0 +1,45 @@
1
+ import { FunctionComponent, useState } from 'react';
2
+ import Message from '@patternfly/chatbot/dist/dynamic/Message';
3
+ import patternflyAvatar from './patternfly_avatar.jpg';
4
+ import { Checkbox, Flex, FlexItem } from '@patternfly/react-core';
5
+
6
+ export const MessageWithToolCallExample: FunctionComponent = () => {
7
+ const [toolCallsAreLoading, setToolCallsAreLoading] = useState(false);
8
+ return (
9
+ <Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsXl' }}>
10
+ <Checkbox
11
+ label="Tool calls are loading"
12
+ id="tool-calls-are-loading"
13
+ isChecked={toolCallsAreLoading}
14
+ onChange={() => {
15
+ setToolCallsAreLoading(!toolCallsAreLoading);
16
+ }}
17
+ />
18
+ <FlexItem>
19
+ <Message
20
+ name="Bot"
21
+ role="bot"
22
+ avatar={patternflyAvatar}
23
+ content="This example has a static tool call title:"
24
+ toolCall={{
25
+ titleText: "Calling 'awesome_tool'",
26
+ loadingText: "Loading 'awesome_tool'",
27
+ isLoading: toolCallsAreLoading
28
+ }}
29
+ />
30
+ <Message
31
+ name="Bot"
32
+ role="bot"
33
+ avatar={patternflyAvatar}
34
+ content="This example has an expandable tool call title, with an additional description::"
35
+ toolCall={{
36
+ titleText: "Calling 'awesome_tool_expansion'",
37
+ expandableContent: 'This is the expandable content for the tool call.',
38
+ isLoading: toolCallsAreLoading,
39
+ loadingText: "Loading 'awesome_tool_expansion'"
40
+ }}
41
+ />
42
+ </FlexItem>
43
+ </Flex>
44
+ );
45
+ };
@@ -199,6 +199,16 @@ Because this is an evolving area, this card content is currently fully customiza
199
199
 
200
200
  ```
201
201
 
202
+ ### Messages with tool calls
203
+
204
+ If you are using [model context protocol (MCP)](https://www.redhat.com/en/blog/model-context-protocol-discover-missing-link-ai-integration), you can share tool call information with users as part of a message. To display a tool card card, pass `toolCalls` to `<Message>`. This card contains a title, actions for running the tool and cancelling, and optional descriptive text.
205
+
206
+ You can also display a loading animation until the tool call can be run. To visualize loading behavior in this example, select the "Tool calls are loading" checkbox.
207
+
208
+ ```js file="./MessageWithToolCall.tsx"
209
+
210
+ ```
211
+
202
212
  ### Messages with quick start tiles
203
213
 
204
214
  [Quick start](/extensions/quick-starts/) tiles can be added to messages via the `quickStarts` prop. Users can initiate the quick start from a link within the message tile.
@@ -123,7 +123,7 @@ This demo displays an embedded ChatBot. Embedded ChatBots are meant to be placed
123
123
  This demo displays a ChatBot in a static, inline drawer. This demo includes:
124
124
 
125
125
  1. An empty [PatternFly page](/components/page) with a sidebar and masthead.
126
- 2. A [basic ChatBot](#basic-chatbot), placed beside the page content. It does not overlay the page content, cannot be minimized, and does not allow you to change the display mode by default.
126
+ 2. A [basic ChatBot](#basic-chatbot), placed beside the page content. It does not overlay the page content and does not allow you to change the display mode by default.
127
127
 
128
128
  **Note:** The inline drawer ChatBot is built to fit and perform within a drawer, but the implementation of the drawer is up to you. This drawer can look different for each product, but will often be placed to the side of the page, inline with the page content.
129
129
 
@@ -52,6 +52,7 @@ import { rehypeMoveImagesOutOfParagraphs } from './Plugins/rehypeMoveImagesOutOf
52
52
  import ToolResponse, { ToolResponseProps } from '../ToolResponse';
53
53
  import DeepThinking, { DeepThinkingProps } from '../DeepThinking';
54
54
  import SuperscriptMessage from './SuperscriptMessage/SuperscriptMessage';
55
+ import ToolCall, { ToolCallProps } from '../ToolCall';
55
56
 
56
57
  export interface MessageAttachment {
57
58
  /** Name of file attached to the message */
@@ -200,6 +201,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
200
201
  deepThinking?: DeepThinkingProps;
201
202
  /** Allows passing additional props down to remark-gfm. See https://github.com/remarkjs/remark-gfm?tab=readme-ov-file#options for options */
202
203
  remarkGfmProps?: Options;
204
+ /** Props for a tool call message */
205
+ toolCall?: ToolCallProps;
203
206
  }
204
207
 
205
208
  export const MessageBase: FunctionComponent<MessageProps> = ({
@@ -245,6 +248,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
245
248
  toolResponse,
246
249
  deepThinking,
247
250
  remarkGfmProps,
251
+ toolCall,
248
252
  ...props
249
253
  }: MessageProps) => {
250
254
  const [messageText, setMessageText] = useState(content);
@@ -485,6 +489,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
485
489
  {afterMainContent && <>{afterMainContent}</>}
486
490
  {toolResponse && <ToolResponse {...toolResponse} />}
487
491
  {deepThinking && <DeepThinking {...deepThinking} />}
492
+ {toolCall && <ToolCall {...toolCall} />}
488
493
  {!isLoading && sources && <SourcesCard {...sources} isCompact={isCompact} />}
489
494
  {quickStarts && quickStarts.quickStart && (
490
495
  <QuickStartTile
@@ -0,0 +1,37 @@
1
+ .pf-chatbot__tool-call {
2
+ --pf-v6-c-card--BorderColor: var(--pf-t--global--border--color--control--read-only);
3
+ --pf-v6-c-card--BorderRadius: var(--pf-t--global--border--radius--small);
4
+
5
+ overflow: unset;
6
+ row-gap: var(--pf-t--global--spacer--sm);
7
+
8
+ .pf-chatbot__tool-call-title-content {
9
+ display: flex;
10
+ gap: var(--pf-t--global--spacer--xs);
11
+ align-items: center;
12
+ }
13
+
14
+ .pf-chatbot__tool-call-title:not(:has(.pf-chatbot__tool-call-expandable-section)) {
15
+ .pf-chatbot__tool-call-title-text {
16
+ color: var(--pf-t--global--text--color--regular);
17
+ font-size: var(--pf-t--global--font--size--body--default);
18
+ font-weight: var(--pf-t--global--font--weight--body--default);
19
+ }
20
+ }
21
+
22
+ .pf-chatbot__tool-call-title {
23
+ overflow: unset;
24
+ }
25
+
26
+ .pf-chatbot__tool-call-expandable-section {
27
+ --pf-v6-c-expandable-section--Gap: var(--pf-t--global--spacer--xs);
28
+
29
+ .pf-v6-c-expandable-section__content {
30
+ color: var(--pf-t--global--text--color--subtle);
31
+ }
32
+ }
33
+
34
+ .pf-chatbot__tool-call-action-list {
35
+ justify-content: flex-end;
36
+ }
37
+ }
@@ -0,0 +1,184 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import '@testing-library/jest-dom';
4
+ import ToolCall from './ToolCall';
5
+
6
+ describe('ToolCall', () => {
7
+ const defaultProps = {
8
+ titleText: 'ToolCall Title',
9
+ loadingText: 'Loading ToolCall'
10
+ };
11
+
12
+ it('Renders with passed in titleText', () => {
13
+ render(<ToolCall {...defaultProps} />);
14
+ expect(screen.getByText(defaultProps.titleText)).toBeVisible();
15
+ });
16
+
17
+ it('Does not render with passed in loadingText when isLoading is false', () => {
18
+ render(<ToolCall {...defaultProps} />);
19
+ expect(screen.queryByText(defaultProps.loadingText)).not.toBeInTheDocument();
20
+ });
21
+
22
+ it('Renders with passed in loadingText when isLoading is true', () => {
23
+ render(<ToolCall {...defaultProps} isLoading />);
24
+ expect(screen.getByText(defaultProps.loadingText)).toBeVisible();
25
+ });
26
+
27
+ it('Does not render titleText when isLoading is true', () => {
28
+ render(<ToolCall {...defaultProps} isLoading />);
29
+ expect(screen.queryByText(defaultProps.titleText)).not.toBeInTheDocument();
30
+ });
31
+
32
+ it('Passes spinnerProps to Spinner', () => {
33
+ render(<ToolCall {...defaultProps} isLoading spinnerProps={{ id: 'spinner-test-id' }} />);
34
+
35
+ expect(screen.getByRole('progressbar')).toHaveAttribute('id', 'spinner-test-id');
36
+ });
37
+
38
+ it('Does not render expandable toggle by default', () => {
39
+ render(<ToolCall {...defaultProps} />);
40
+ expect(screen.queryByRole('button', { name: defaultProps.titleText })).not.toBeInTheDocument();
41
+ });
42
+
43
+ it('Renders titleText inside expandable toggle when expandableContent is passed', () => {
44
+ render(<ToolCall {...defaultProps} expandableContent="Expandable Content" />);
45
+ expect(screen.getByRole('button', { name: defaultProps.titleText })).toBeVisible();
46
+ });
47
+
48
+ it('Does not render expandable content when expandableContent is passed by default', () => {
49
+ render(<ToolCall {...defaultProps} expandableContent="Expandable Content" />);
50
+ expect(screen.queryByText('Expandable Content')).not.toBeVisible();
51
+ });
52
+
53
+ it('Renders expandable content when expandableContent is passed and toggle is clicked', async () => {
54
+ const user = userEvent.setup();
55
+ render(<ToolCall {...defaultProps} expandableContent="Expandable Content" />);
56
+ await user.click(screen.getByRole('button', { name: defaultProps.titleText }));
57
+
58
+ expect(screen.getByText('Expandable Content')).toBeVisible();
59
+ });
60
+
61
+ it('Passes expandableSectionProps to ExpandableSection', () => {
62
+ render(
63
+ <ToolCall
64
+ {...defaultProps}
65
+ expandableContent="Expandable Content"
66
+ expandableSectionProps={{ id: 'expandable-section-test-id', isExpanded: true }}
67
+ />
68
+ );
69
+ expect(screen.getByRole('region').parentElement).toHaveAttribute('id', 'expandable-section-test-id');
70
+ });
71
+
72
+ it('Renders "run" action button by default', () => {
73
+ render(<ToolCall {...defaultProps} />);
74
+ expect(screen.getByRole('button', { name: 'Run tool' })).toBeVisible();
75
+ });
76
+
77
+ it('Renders "cancel" action button by default', () => {
78
+ render(<ToolCall {...defaultProps} />);
79
+ expect(screen.getByRole('button', { name: 'Cancel' })).toBeVisible();
80
+ });
81
+
82
+ it('Does not render "run" action button when isLoading is true', () => {
83
+ render(<ToolCall {...defaultProps} isLoading />);
84
+ expect(screen.queryByRole('button', { name: 'Run tool' })).not.toBeInTheDocument();
85
+ });
86
+
87
+ it('Does not render "cancel" action button when isLoading is true', () => {
88
+ render(<ToolCall {...defaultProps} isLoading />);
89
+ expect(screen.queryByRole('button', { name: 'Cancel' })).not.toBeInTheDocument();
90
+ });
91
+
92
+ it('Renders runButtonText when passed', () => {
93
+ render(<ToolCall {...defaultProps} runButtonText="Run my custom tool" />);
94
+ expect(screen.getByRole('button', { name: 'Run my custom tool' })).toBeVisible();
95
+ });
96
+
97
+ it('Renders cancelButtonText when passed', () => {
98
+ render(<ToolCall {...defaultProps} cancelButtonText="Cancel my custom tool" />);
99
+ expect(screen.getByRole('button', { name: 'Cancel my custom tool' })).toBeVisible();
100
+ });
101
+
102
+ it('Passes runButtonProps to Button', () => {
103
+ render(<ToolCall {...defaultProps} runButtonProps={{ id: 'run-button-test-id' }} />);
104
+ expect(screen.getByRole('button', { name: 'Run tool' })).toHaveAttribute('id', 'run-button-test-id');
105
+ });
106
+
107
+ it('Passes cancelButtonProps to Button', () => {
108
+ render(<ToolCall {...defaultProps} cancelButtonProps={{ id: 'cancel-button-test-id' }} />);
109
+ expect(screen.getByRole('button', { name: 'Cancel' })).toHaveAttribute('id', 'cancel-button-test-id');
110
+ });
111
+
112
+ it('Passes runActionItemProps to ActionListItem', () => {
113
+ render(<ToolCall {...defaultProps} runActionItemProps={{ id: 'run-action-item-test-id' }} />);
114
+ expect(screen.getByRole('button', { name: 'Run tool' }).parentElement).toHaveAttribute(
115
+ 'id',
116
+ 'run-action-item-test-id'
117
+ );
118
+ });
119
+
120
+ it('Passes cancelActionItemProps to ActionListItem', () => {
121
+ render(<ToolCall {...defaultProps} cancelActionItemProps={{ id: 'cancel-action-item-test-id' }} />);
122
+ expect(screen.getByRole('button', { name: 'Cancel' }).parentElement).toHaveAttribute(
123
+ 'id',
124
+ 'cancel-action-item-test-id'
125
+ );
126
+ });
127
+
128
+ it('Passes actionListProps to ActionList', () => {
129
+ render(<ToolCall {...defaultProps} actionListProps={{ id: 'action-list-test-id' }} />);
130
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#action-list-test-id')).toBeVisible();
131
+ });
132
+
133
+ it('Passes actionListGroupProps to ActionListGroup', () => {
134
+ render(<ToolCall {...defaultProps} actionListGroupProps={{ id: 'action-list-group-test-id' }} />);
135
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#action-list-group-test-id')).toBeVisible();
136
+ });
137
+
138
+ it('Passes actionListItemProps to ActionListItem for default actions', () => {
139
+ render(<ToolCall {...defaultProps} actionListItemProps={{ className: 'action-list-item-test-class' }} />);
140
+ expect(screen.getByRole('button', { name: 'Run tool' }).parentElement).toHaveClass('action-list-item-test-class');
141
+ expect(screen.getByRole('button', { name: 'Cancel' }).parentElement).toHaveClass('action-list-item-test-class');
142
+ });
143
+
144
+ it('Renders custom actions instead of default actions when actions are passed', () => {
145
+ render(
146
+ <ToolCall
147
+ {...defaultProps}
148
+ actions={[<div key="custom-action-1">Custom action 1</div>, <div key="custom-action-2">Custom action 2</div>]}
149
+ />
150
+ );
151
+
152
+ expect(screen.getByText('Custom action 1')).toBeVisible();
153
+ expect(screen.getByText('Custom action 2')).toBeVisible();
154
+ expect(screen.queryByRole('button', { name: 'Run tool' })).not.toBeInTheDocument();
155
+ expect(screen.queryByRole('button', { name: 'Cancel' })).not.toBeInTheDocument();
156
+ });
157
+
158
+ it('Passes actionListItemProps to ActionListItem for custom actions', () => {
159
+ render(
160
+ <ToolCall
161
+ {...defaultProps}
162
+ actions={[<div key="custom-action-1">Custom action 1</div>, <div key="custom-action-2">Custom action 2</div>]}
163
+ actionListItemProps={{ className: 'action-list-item-test-class' }}
164
+ />
165
+ );
166
+ expect(screen.getByText('Custom action 1').parentElement).toHaveClass('action-list-item-test-class');
167
+ expect(screen.getByText('Custom action 2').parentElement).toHaveClass('action-list-item-test-class');
168
+ });
169
+
170
+ it('Passes cardProps to Card', () => {
171
+ render(<ToolCall {...defaultProps} cardProps={{ id: 'card-test-id' }} />);
172
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#card-test-id')).toBeVisible();
173
+ });
174
+
175
+ it('Passes cardBodyProps to CardBody', () => {
176
+ render(<ToolCall {...defaultProps} cardBodyProps={{ id: 'card-body-test-id' }} />);
177
+ expect(screen.getByText(defaultProps.titleText).closest('#card-body-test-id')).toBeVisible();
178
+ });
179
+
180
+ it('Passes cardFooterProps to CardFooter', () => {
181
+ render(<ToolCall {...defaultProps} cardFooterProps={{ id: 'card-footer-test-id' }} />);
182
+ expect(screen.getByRole('button', { name: 'Run tool' }).closest('#card-footer-test-id')).toBeVisible();
183
+ });
184
+ });