@automattic/jetpack-ai-client 0.27.3 → 0.27.5

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.27.5] - 2025-03-24
9
+ ### Changed
10
+ - Update dependencies. [#42565]
11
+
12
+ ### Fixed
13
+ - AI Client: Improve performance by optimizing state management in the AI feature hook. [#42536]
14
+ - AI Controls: Prevent console warnings by increasing compatibility of buttons. [#42636]
15
+
16
+ ## [0.27.4] - 2025-03-18
17
+ ### Changed
18
+ - Update package dependencies. [#42509]
19
+
8
20
  ## [0.27.3] - 2025-03-17
9
21
  ### Changed
10
22
  - Internal updates.
@@ -557,6 +569,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
557
569
  - AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
558
570
  - Updated package dependencies. [#31468] [#31659] [#31785]
559
571
 
572
+ [0.27.5]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.4...v0.27.5
573
+ [0.27.4]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.3...v0.27.4
560
574
  [0.27.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.2...v0.27.3
561
575
  [0.27.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.1...v0.27.2
562
576
  [0.27.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.0...v0.27.1
@@ -2,7 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  /**
3
3
  * External dependencies
4
4
  */
5
- import { Button, ButtonGroup } from '@wordpress/components';
5
+ import { Button, Flex } from '@wordpress/components';
6
6
  import { useKeyboardShortcut } from '@wordpress/compose';
7
7
  import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
8
8
  import { __ } from '@wordpress/i18n';
@@ -75,7 +75,7 @@ export function BlockAIControl({ disabled = false, value = '', placeholder = '',
75
75
  }, {
76
76
  target: promptUserInputRef,
77
77
  });
78
- const actions = (_jsxs(_Fragment, { children: [(!showAccept || editRequest) && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: !loading ? (_jsxs(_Fragment, { children: [editRequest && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: cancelEdit, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), showRemove && !editRequest && !value?.length && onDiscard && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: discardHandler, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), value?.length > 0 && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }))] })) : (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onStop, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Stop', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })) })), showAccept && !editRequest && (_jsxs("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: [(value?.length > 0 || lastValue === null) && (_jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Discard', 'jetpack-ai-client'), onClick: discardHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: trash }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Regenerate', 'jetpack-ai-client'), onClick: () => onSend?.(value), tooltipPosition: "top", disabled: !value?.length || value === null || disabled, children: _jsx(Icon, { icon: regenerate }) })] })), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onAccept, variant: "primary", label: acceptLabel, children: showButtonLabels ? acceptLabel : _jsx(Icon, { icon: check }) })] }))] }));
78
+ const actions = (_jsxs(_Fragment, { children: [(!showAccept || editRequest) && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: !loading ? (_jsxs(_Fragment, { children: [editRequest && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: cancelEdit, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), showRemove && !editRequest && !value?.length && onDiscard && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: discardHandler, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), value?.length > 0 && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }))] })) : (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onStop, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Stop', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })) })), showAccept && !editRequest && (_jsxs("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: [(value?.length > 0 || lastValue === null) && (_jsxs(Flex, { gap: 1, role: "group", className: "jetpack-components-ai-control__button-group", children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Discard', 'jetpack-ai-client'), onClick: discardHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: trash }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Regenerate', 'jetpack-ai-client'), onClick: () => onSend?.(value), tooltipPosition: "top", disabled: !value?.length || value === null || disabled, children: _jsx(Icon, { icon: regenerate }) })] })), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onAccept, variant: "primary", label: acceptLabel, children: showButtonLabels ? acceptLabel : _jsx(Icon, { icon: check }) })] }))] }));
79
79
  const message = showGuideLine &&
80
80
  !loading &&
81
81
  !editRequest &&
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  /**
3
3
  * External dependencies
4
4
  */
5
- import { Button, ButtonGroup } from '@wordpress/components';
5
+ import { Button, Flex } from '@wordpress/components';
6
6
  import { useKeyboardShortcut } from '@wordpress/compose';
7
7
  import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
8
8
  import { __ } from '@wordpress/i18n';
@@ -74,7 +74,7 @@ export function ExtensionAIControl({ className, disabled = false, value = '', pl
74
74
  }, {
75
75
  target: promptUserInputRef,
76
76
  });
77
- const actions = (_jsx(_Fragment, { children: loading ? (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: stopHandler, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? __('Stop', 'jetpack-ai-client') : _jsx(Icon, { icon: closeSmall }) })) : (_jsxs(_Fragment, { children: [value?.length > 0 && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }) })), isDone && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Undo', 'jetpack-ai-client'), onClick: undoHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: undo }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Close', 'jetpack-ai-client'), onClick: closeHandler, variant: "tertiary", children: __('Close', 'jetpack-ai-client') })] }) }))] })) }));
77
+ const actions = (_jsx(_Fragment, { children: loading ? (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: stopHandler, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? __('Stop', 'jetpack-ai-client') : _jsx(Icon, { icon: closeSmall }) })) : (_jsxs(_Fragment, { children: [value?.length > 0 && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }) })), isDone && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsxs(Flex, { gap: 1, role: "group", className: "jetpack-components-ai-control__button-group", children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Undo', 'jetpack-ai-client'), onClick: undoHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: undo }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Close', 'jetpack-ai-client'), onClick: closeHandler, variant: "tertiary", children: __('Close', 'jetpack-ai-client') })] }) }))] })) }));
78
78
  let message = null;
79
79
  if (error?.message) {
80
80
  message = (_jsx(ErrorMessage, { error: error.message, code: error.code, onTryAgainClick: tryAgainHandler, onUpgradeClick: upgradeHandler, upgradeUrl: upgradeUrl }));
@@ -3,35 +3,29 @@
3
3
  */
4
4
  import { PLAN_TYPE_FREE, usePlanType as getPlanType, } from '@automattic/jetpack-shared-extension-utils';
5
5
  import { useDispatch, useSelect } from '@wordpress/data';
6
+ import { useMemo } from '@wordpress/element';
6
7
  /**
7
8
  * Hook to get properties for AiFeature
8
9
  * @return {object} - Object containing properties for AiFeature.
9
10
  */
10
11
  export default function useAiFeature() {
11
- const { data, loading, requestsLimit, requestsCount } = useSelect(select => {
12
- const { getAiAssistantFeature, getIsRequestingAiAssistantFeature } = select('wordpress-com/plans');
13
- const featureData = getAiAssistantFeature();
14
- const { currentTier, usagePeriod, requestsCount: allTimeRequestsCount, requestsLimit: freeRequestsLimit, } = featureData;
15
- const planType = getPlanType(currentTier);
16
- const currentTierLimit = currentTier?.limit || freeRequestsLimit;
17
- const actualRequestsCount = planType === PLAN_TYPE_FREE ? allTimeRequestsCount : usagePeriod?.requestsCount;
18
- const actualRequestsLimit = planType === PLAN_TYPE_FREE ? freeRequestsLimit : currentTierLimit;
12
+ const data = useSelect(select => select('wordpress-com/plans').getAiAssistantFeature(), []);
13
+ const loading = useSelect(select => select('wordpress-com/plans').getIsRequestingAiAssistantFeature(), []);
14
+ const { fetchAiAssistantFeature: loadFeatures, increaseAiAssistantRequestsCount: increaseRequestsCount, dequeueAiAssistantFeatureAsyncRequest: dequeueAsyncRequest, } = useDispatch('wordpress-com/plans');
15
+ return useMemo(() => {
16
+ const planType = getPlanType(data?.currentTier);
17
+ const currentTierLimit = data?.currentTier?.limit || data?.requestsLimit;
18
+ const requestsCount = planType === PLAN_TYPE_FREE ? data?.requestsCount : data?.usagePeriod?.requestsCount;
19
+ const requestsLimit = planType === PLAN_TYPE_FREE ? data?.requestsLimit : currentTierLimit;
19
20
  return {
20
- data: featureData,
21
- loading: getIsRequestingAiAssistantFeature(),
22
- requestsCount: actualRequestsCount,
23
- requestsLimit: actualRequestsLimit,
21
+ ...data,
22
+ requestsCount,
23
+ requestsLimit,
24
+ loading,
25
+ error: null,
26
+ refresh: loadFeatures,
27
+ increaseRequestsCount,
28
+ dequeueAsyncRequest,
24
29
  };
25
- }, []);
26
- const { fetchAiAssistantFeature: loadFeatures, increaseAiAssistantRequestsCount: increaseRequestsCount, dequeueAiAssistantFeatureAsyncRequest: dequeueAsyncRequest, } = useDispatch('wordpress-com/plans');
27
- return {
28
- ...data,
29
- requestsCount,
30
- requestsLimit,
31
- loading,
32
- error: null,
33
- refresh: loadFeatures,
34
- increaseRequestsCount,
35
- dequeueAsyncRequest,
36
- };
30
+ }, [data, loading, loadFeatures, increaseRequestsCount, dequeueAsyncRequest]);
37
31
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.27.3",
4
+ "version": "0.27.5",
5
5
  "description": "A JS client for consuming Jetpack AI services",
6
6
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme",
7
7
  "bugs": {
@@ -24,15 +24,15 @@
24
24
  },
25
25
  "type": "module",
26
26
  "devDependencies": {
27
- "@storybook/addon-actions": "8.5.8",
28
- "@storybook/blocks": "8.5.8",
29
- "@storybook/preview-api": "8.5.8",
30
- "@storybook/react": "8.5.8",
27
+ "@storybook/addon-actions": "8.6.7",
28
+ "@storybook/blocks": "8.6.7",
29
+ "@storybook/preview-api": "8.6.7",
30
+ "@storybook/react": "8.6.7",
31
31
  "@types/markdown-it": "14.1.2",
32
32
  "@types/turndown": "5.0.5",
33
33
  "jest": "^29.6.2",
34
34
  "jest-environment-jsdom": "29.7.0",
35
- "storybook": "8.5.8",
35
+ "storybook": "8.6.7",
36
36
  "typescript": "5.0.4"
37
37
  },
38
38
  "exports": {
@@ -45,9 +45,9 @@
45
45
  "types": "./build/index.d.ts",
46
46
  "dependencies": {
47
47
  "@automattic/jetpack-base-styles": "^0.6.44",
48
- "@automattic/jetpack-components": "^0.68.2",
49
- "@automattic/jetpack-connection": "^0.39.1",
50
- "@automattic/jetpack-shared-extension-utils": "^0.18.1",
48
+ "@automattic/jetpack-components": "^0.70.0",
49
+ "@automattic/jetpack-connection": "^0.39.4",
50
+ "@automattic/jetpack-shared-extension-utils": "^0.18.5",
51
51
  "@microsoft/fetch-event-source": "2.0.1",
52
52
  "@types/jest": "29.5.14",
53
53
  "@types/react": "18.3.18",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { Button, ButtonGroup } from '@wordpress/components';
4
+ import { Button, Flex } from '@wordpress/components';
5
5
  import { useKeyboardShortcut } from '@wordpress/compose';
6
6
  import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
7
7
  import { __ } from '@wordpress/i18n';
@@ -224,7 +224,7 @@ export function BlockAIControl(
224
224
  { showAccept && ! editRequest && (
225
225
  <div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
226
226
  { ( value?.length > 0 || lastValue === null ) && (
227
- <ButtonGroup>
227
+ <Flex gap={ 1 } role="group" className="jetpack-components-ai-control__button-group">
228
228
  <Button
229
229
  className="jetpack-components-ai-control__controls-prompt_button"
230
230
  label={ __( 'Discard', 'jetpack-ai-client' ) }
@@ -242,7 +242,7 @@ export function BlockAIControl(
242
242
  >
243
243
  <Icon icon={ regenerate } />
244
244
  </Button>
245
- </ButtonGroup>
245
+ </Flex>
246
246
  ) }
247
247
  <Button
248
248
  className="jetpack-components-ai-control__controls-prompt_button"
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { Button, ButtonGroup } from '@wordpress/components';
4
+ import { Button, Flex } from '@wordpress/components';
5
5
  import { useKeyboardShortcut } from '@wordpress/compose';
6
6
  import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
7
7
  import { __ } from '@wordpress/i18n';
@@ -190,7 +190,7 @@ export function ExtensionAIControl(
190
190
  ) }
191
191
  { isDone && (
192
192
  <div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
193
- <ButtonGroup>
193
+ <Flex gap={ 1 } role="group" className="jetpack-components-ai-control__button-group">
194
194
  <Button
195
195
  className="jetpack-components-ai-control__controls-prompt_button"
196
196
  label={ __( 'Undo', 'jetpack-ai-client' ) }
@@ -207,7 +207,7 @@ export function ExtensionAIControl(
207
207
  >
208
208
  { __( 'Close', 'jetpack-ai-client' ) }
209
209
  </Button>
210
- </ButtonGroup>
210
+ </Flex>
211
211
  </div>
212
212
  ) }
213
213
  </>
@@ -6,6 +6,7 @@ import {
6
6
  usePlanType as getPlanType,
7
7
  } from '@automattic/jetpack-shared-extension-utils';
8
8
  import { useDispatch, useSelect } from '@wordpress/data';
9
+ import { useMemo } from '@wordpress/element';
9
10
  import type { WordPressPlansSelectors } from '@automattic/jetpack-shared-extension-utils/store/wordpress-com';
10
11
 
11
12
  /**
@@ -13,35 +14,19 @@ import type { WordPressPlansSelectors } from '@automattic/jetpack-shared-extensi
13
14
  * @return {object} - Object containing properties for AiFeature.
14
15
  */
15
16
  export default function useAiFeature() {
16
- const { data, loading, requestsLimit, requestsCount } = useSelect( select => {
17
- const { getAiAssistantFeature, getIsRequestingAiAssistantFeature } = select(
18
- 'wordpress-com/plans'
19
- ) as WordPressPlansSelectors;
20
-
21
- const featureData = getAiAssistantFeature();
22
-
23
- const {
24
- currentTier,
25
- usagePeriod,
26
- requestsCount: allTimeRequestsCount,
27
- requestsLimit: freeRequestsLimit,
28
- } = featureData;
29
-
30
- const planType = getPlanType( currentTier );
31
-
32
- const currentTierLimit = currentTier?.limit || freeRequestsLimit;
33
-
34
- const actualRequestsCount =
35
- planType === PLAN_TYPE_FREE ? allTimeRequestsCount : usagePeriod?.requestsCount;
36
- const actualRequestsLimit = planType === PLAN_TYPE_FREE ? freeRequestsLimit : currentTierLimit;
37
-
38
- return {
39
- data: featureData,
40
- loading: getIsRequestingAiAssistantFeature(),
41
- requestsCount: actualRequestsCount,
42
- requestsLimit: actualRequestsLimit,
43
- };
44
- }, [] );
17
+ const data = useSelect(
18
+ select =>
19
+ ( select( 'wordpress-com/plans' ) as WordPressPlansSelectors ).getAiAssistantFeature(),
20
+ []
21
+ );
22
+
23
+ const loading = useSelect(
24
+ select =>
25
+ (
26
+ select( 'wordpress-com/plans' ) as WordPressPlansSelectors
27
+ ).getIsRequestingAiAssistantFeature(),
28
+ []
29
+ );
45
30
 
46
31
  const {
47
32
  fetchAiAssistantFeature: loadFeatures,
@@ -49,14 +34,24 @@ export default function useAiFeature() {
49
34
  dequeueAiAssistantFeatureAsyncRequest: dequeueAsyncRequest,
50
35
  } = useDispatch( 'wordpress-com/plans' );
51
36
 
52
- return {
53
- ...data,
54
- requestsCount,
55
- requestsLimit,
56
- loading,
57
- error: null, // @todo: handle error at store level
58
- refresh: loadFeatures,
59
- increaseRequestsCount,
60
- dequeueAsyncRequest,
61
- };
37
+ return useMemo( () => {
38
+ const planType = getPlanType( data?.currentTier );
39
+ const currentTierLimit = data?.currentTier?.limit || data?.requestsLimit;
40
+
41
+ const requestsCount =
42
+ planType === PLAN_TYPE_FREE ? data?.requestsCount : data?.usagePeriod?.requestsCount;
43
+
44
+ const requestsLimit = planType === PLAN_TYPE_FREE ? data?.requestsLimit : currentTierLimit;
45
+
46
+ return {
47
+ ...data,
48
+ requestsCount,
49
+ requestsLimit,
50
+ loading,
51
+ error: null, // @todo: handle error at store level
52
+ refresh: loadFeatures,
53
+ increaseRequestsCount,
54
+ dequeueAsyncRequest,
55
+ };
56
+ }, [ data, loading, loadFeatures, increaseRequestsCount, dequeueAsyncRequest ] );
62
57
  }