@automattic/jetpack-ai-client 0.28.0 → 0.29.0

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,14 @@ 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.29.0] - 2025-05-19
9
+ ### Added
10
+ - AI Assistant: Retrieve Chrome AI token from AI Features response and inject it from the frontend. [#43442]
11
+
12
+ ## [0.28.1] - 2025-05-15
13
+ ### Fixed
14
+ - AI Assistant: Shorten AI excerpt if the built-in AI model doesn't respect the word count limit. [#43433]
15
+
8
16
  ## [0.28.0] - 2025-05-12
9
17
  ### Changed
10
18
  - AI Assistant: Propagate the AI model used in the AI requests. [#43390]
@@ -608,6 +616,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
608
616
  - AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
609
617
  - Updated package dependencies. [#31468] [#31659] [#31785]
610
618
 
619
+ [0.29.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.28.1...v0.29.0
620
+ [0.28.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.28.0...v0.28.1
611
621
  [0.28.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.10...v0.28.0
612
622
  [0.27.10]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.9...v0.27.10
613
623
  [0.27.9]: https://github.com/Automattic/jetpack-ai-client/compare/v0.27.8...v0.27.9
@@ -82,7 +82,7 @@ export default class ChromeAISuggestionsEventSource extends EventTarget {
82
82
  }
83
83
  // Helper function to format summarizer options
84
84
  getSummarizerOptions(tone, wordCount) {
85
- let sharedContext = `The summary you write should contain approximately ${wordCount ?? 50} words long. Strive for precision in word count without compromising clarity and significance`;
85
+ let sharedContext = `The summary you write should contain strictly less than ${wordCount ?? 50} words. Strive for precision in word count without compromising clarity and significance`;
86
86
  if (tone) {
87
87
  sharedContext += `\n - Write with a ${tone} tone.\n`;
88
88
  }
@@ -99,8 +99,6 @@ export default class ChromeAISuggestionsEventSource extends EventTarget {
99
99
  if (!('Summarizer' in self)) {
100
100
  return;
101
101
  }
102
- // eslint-disable-next-line no-console
103
- console.log('Summarizer is available');
104
102
  const availability = await self.Summarizer.availability();
105
103
  if (availability === 'unavailable') {
106
104
  return;
@@ -112,7 +110,12 @@ export default class ChromeAISuggestionsEventSource extends EventTarget {
112
110
  }
113
111
  try {
114
112
  const context = `Write with a ${tone} tone.`;
115
- const summary = await summarizer.summarize(text, { context: context });
113
+ let summary = await summarizer.summarize(text, { context: context });
114
+ wordCount = wordCount ?? 50;
115
+ // gemini-nano has a tendency to exceed the word count, so we need to check and summarize again if necessary
116
+ if (summary.split(' ').length > wordCount) {
117
+ summary = await summarizer.summarize(summary, { context: context });
118
+ }
116
119
  this.processEvent({
117
120
  id: '',
118
121
  event: 'summary',
@@ -30,4 +30,5 @@ export default function useAiFeature(): {
30
30
  };
31
31
  };
32
32
  featuresControl?: import("@automattic/jetpack-shared-extension-utils/store/wordpress-com/types").FeaturesControl;
33
+ chromeAiTokens?: import("@automattic/jetpack-shared-extension-utils/store/wordpress-com/types").ChromeAiTokens;
33
34
  };
@@ -3,7 +3,7 @@
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
+ import { useMemo, useEffect } from '@wordpress/element';
7
7
  /**
8
8
  * Hook to get properties for AiFeature
9
9
  * @return {object} - Object containing properties for AiFeature.
@@ -12,6 +12,21 @@ export default function useAiFeature() {
12
12
  const data = useSelect(select => select('wordpress-com/plans').getAiAssistantFeature(), []);
13
13
  const loading = useSelect(select => select('wordpress-com/plans').getIsRequestingAiAssistantFeature(), []);
14
14
  const { fetchAiAssistantFeature: loadFeatures, increaseAiAssistantRequestsCount: increaseRequestsCount, dequeueAiAssistantFeatureAsyncRequest: dequeueAsyncRequest, } = useDispatch('wordpress-com/plans');
15
+ useEffect(() => {
16
+ if (!loading && data) {
17
+ // Check if the meta tag already exists
18
+ const existingMeta = document.querySelector('meta[http-equiv="origin-trial"]');
19
+ if (!existingMeta && data?.chromeAiTokens) {
20
+ // iterate through chromeAiTokens and create a meta tag for each one
21
+ Object.keys(data.chromeAiTokens).forEach(token => {
22
+ const otMeta = document.createElement('meta');
23
+ otMeta.httpEquiv = 'origin-trial';
24
+ otMeta.content = data.chromeAiTokens[token];
25
+ document.head.appendChild(otMeta);
26
+ });
27
+ }
28
+ }
29
+ }, [loading, data]);
15
30
  return useMemo(() => {
16
31
  const planType = getPlanType(data?.currentTier);
17
32
  const currentTierLimit = data?.currentTier?.limit || data?.requestsLimit;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.28.0",
4
+ "version": "0.29.0",
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": {
@@ -46,9 +46,9 @@
46
46
  "types": "./build/index.d.ts",
47
47
  "dependencies": {
48
48
  "@automattic/jetpack-base-styles": "^0.7.4",
49
- "@automattic/jetpack-components": "^0.73.0",
50
- "@automattic/jetpack-connection": "^0.39.14",
51
- "@automattic/jetpack-shared-extension-utils": "^0.19.3",
49
+ "@automattic/jetpack-components": "^0.73.1",
50
+ "@automattic/jetpack-connection": "^0.39.15",
51
+ "@automattic/jetpack-shared-extension-utils": "^0.20.0",
52
52
  "@microsoft/fetch-event-source": "2.0.1",
53
53
  "@types/jest": "29.5.14",
54
54
  "@types/react": "18.3.18",
@@ -141,9 +141,9 @@ export default class ChromeAISuggestionsEventSource extends EventTarget {
141
141
 
142
142
  // Helper function to format summarizer options
143
143
  private getSummarizerOptions( tone?: string, wordCount?: number ) {
144
- let sharedContext = `The summary you write should contain approximately ${
144
+ let sharedContext = `The summary you write should contain strictly less than ${
145
145
  wordCount ?? 50
146
- } words long. Strive for precision in word count without compromising clarity and significance`;
146
+ } words. Strive for precision in word count without compromising clarity and significance`;
147
147
 
148
148
  if ( tone ) {
149
149
  sharedContext += `\n - Write with a ${ tone } tone.\n`;
@@ -164,8 +164,7 @@ export default class ChromeAISuggestionsEventSource extends EventTarget {
164
164
  if ( ! ( 'Summarizer' in self ) ) {
165
165
  return;
166
166
  }
167
- // eslint-disable-next-line no-console
168
- console.log( 'Summarizer is available' );
167
+
169
168
  const availability = await self.Summarizer.availability();
170
169
 
171
170
  if ( availability === 'unavailable' ) {
@@ -182,7 +181,15 @@ export default class ChromeAISuggestionsEventSource extends EventTarget {
182
181
 
183
182
  try {
184
183
  const context = `Write with a ${ tone } tone.`;
185
- const summary = await summarizer.summarize( text, { context: context } );
184
+ let summary = await summarizer.summarize( text, { context: context } );
185
+
186
+ wordCount = wordCount ?? 50;
187
+
188
+ // gemini-nano has a tendency to exceed the word count, so we need to check and summarize again if necessary
189
+ if ( summary.split( ' ' ).length > wordCount ) {
190
+ summary = await summarizer.summarize( summary, { context: context } );
191
+ }
192
+
186
193
  this.processEvent( {
187
194
  id: '',
188
195
  event: 'summary',
@@ -6,7 +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
+ import { useMemo, useEffect } from '@wordpress/element';
10
10
  import type { WordPressPlansSelectors } from '@automattic/jetpack-shared-extension-utils/store/wordpress-com';
11
11
 
12
12
  /**
@@ -34,6 +34,22 @@ export default function useAiFeature() {
34
34
  dequeueAiAssistantFeatureAsyncRequest: dequeueAsyncRequest,
35
35
  } = useDispatch( 'wordpress-com/plans' );
36
36
 
37
+ useEffect( () => {
38
+ if ( ! loading && data ) {
39
+ // Check if the meta tag already exists
40
+ const existingMeta = document.querySelector( 'meta[http-equiv="origin-trial"]' );
41
+ if ( ! existingMeta && data?.chromeAiTokens ) {
42
+ // iterate through chromeAiTokens and create a meta tag for each one
43
+ Object.keys( data.chromeAiTokens ).forEach( token => {
44
+ const otMeta = document.createElement( 'meta' );
45
+ otMeta.httpEquiv = 'origin-trial';
46
+ otMeta.content = data.chromeAiTokens[ token ];
47
+ document.head.appendChild( otMeta );
48
+ } );
49
+ }
50
+ }
51
+ }, [ loading, data ] );
52
+
37
53
  return useMemo( () => {
38
54
  const planType = getPlanType( data?.currentTier );
39
55
  const currentTierLimit = data?.currentTier?.limit || data?.requestsLimit;