@automattic/jetpack-ai-client 0.32.1 → 0.33.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,10 @@ 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.33.0] - 2025-06-30
9
+ ### Changed
10
+ - Create custom explat client with public-api fetch for assignments. [#44081]
11
+
8
12
  ## [0.32.1] - 2025-06-24
9
13
  ### Added
10
14
  - Improve error handling on Chrome AI events. [#44048]
@@ -650,6 +654,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
650
654
  - AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
651
655
  - Updated package dependencies. [#31468] [#31659] [#31785]
652
656
 
657
+ [0.33.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.32.1...v0.33.0
653
658
  [0.32.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.32.0...v0.32.1
654
659
  [0.32.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.31.2...v0.32.0
655
660
  [0.31.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.31.1...v0.31.2
@@ -2,7 +2,15 @@
2
2
  * External dependencies
3
3
  */
4
4
  import apiFetchMod from '@wordpress/api-fetch';
5
+ /**
6
+ * Types
7
+ */
8
+ import type { APIFetchOptions } from '@wordpress/api-fetch';
5
9
  declare const apiFetch: typeof apiFetchMod.default;
6
10
  type ApiFetchType = typeof apiFetch extends Function ? typeof apiFetch : typeof apiFetchMod;
7
- declare const _default: ApiFetchType;
11
+ type AugmentedAPIFetchOptions = APIFetchOptions & {
12
+ global?: boolean;
13
+ };
14
+ type AugmentedApiFetchType = (options: AugmentedAPIFetchOptions) => ReturnType<ApiFetchType>;
15
+ declare const _default: AugmentedApiFetchType;
8
16
  export default _default;
@@ -1,9 +1,14 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { initializeExPlat, loadExperimentAssignmentWithAuth } from '@automattic/jetpack-explat';
4
+ import { initializeExPlat, createExPlatClient } from '@automattic/jetpack-explat';
5
5
  import { select } from '@wordpress/data';
6
+ import { addQueryArgs } from '@wordpress/url';
6
7
  import debugFactory from 'debug';
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import apiFetch from "../api-fetch/index.js";
7
12
  const debug = debugFactory('ai-client:chrome-ai-availability');
8
13
  /**
9
14
  * Get the AI Assistant feature.
@@ -14,6 +19,28 @@ function getAiAssistantFeature() {
14
19
  const { getAiAssistantFeature: getFeature } = select('wordpress-com/plans');
15
20
  return getFeature();
16
21
  }
22
+ /**
23
+ * Fetch an experiment assignment.
24
+ *
25
+ * @param {boolean} asConnectedUser - Whether the user is connected.
26
+ * @return {Function} A function that fetches an experiment assignment.
27
+ */
28
+ const fetchExperimentAssignmentWithConnectedUser = async ({ experimentName, }) => {
29
+ const params = {
30
+ experiment_name: experimentName,
31
+ anon_id: undefined,
32
+ as_connected_user: true,
33
+ };
34
+ debug('params', params);
35
+ const assignmentsRequestUrl = addQueryArgs('https://public-api.wordpress.com/wpcom/v2/experiments/0.1.0/assignments/jetpack', params);
36
+ debug('assignmentsRequestUrl', assignmentsRequestUrl);
37
+ return apiFetch({
38
+ url: assignmentsRequestUrl,
39
+ credentials: 'include',
40
+ mode: 'cors',
41
+ global: true,
42
+ });
43
+ };
17
44
  /**
18
45
  * Check if Chrome AI can be enabled.
19
46
  *
@@ -27,7 +54,12 @@ export async function isChromeAIAvailable() {
27
54
  return false;
28
55
  }
29
56
  initializeExPlat();
30
- debug('initialized explat');
57
+ const { loadExperimentAssignment: loadExperimentAssignmentWithAuth } = createExPlatClient({
58
+ fetchExperimentAssignment: fetchExperimentAssignmentWithConnectedUser,
59
+ getAnonId: async () => null,
60
+ logError: debug,
61
+ isDevelopmentMode: false,
62
+ });
31
63
  const { variationName } = await loadExperimentAssignmentWithAuth('calypso_jetpack_ai_gemini_api_202503_v1');
32
64
  debug('variationName', variationName);
33
65
  return variationName === 'treatment';
@@ -39,7 +39,7 @@ export default async function requestJwt({ apiNonce, siteId, expirationTime, } =
39
39
  let data;
40
40
  const isSimple = isSimpleSite();
41
41
  if (!isSimple) {
42
- data = await apiFetch({
42
+ data = (await apiFetch({
43
43
  /*
44
44
  * This endpoint is registered in the Jetpack plugin.
45
45
  * Provably we should move it to another package, but for now it's here.
@@ -51,13 +51,13 @@ export default async function requestJwt({ apiNonce, siteId, expirationTime, } =
51
51
  'X-WP-Nonce': apiNonce,
52
52
  },
53
53
  method: 'POST',
54
- });
54
+ }));
55
55
  }
56
56
  else {
57
- data = await apiFetch({
57
+ data = (await apiFetch({
58
58
  path: '/wpcom/v2/sites/' + siteId + '/jetpack-openai-query/jwt',
59
59
  method: 'POST',
60
- });
60
+ }));
61
61
  }
62
62
  const newTokenData = {
63
63
  token: data.token,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.32.1",
4
+ "version": "0.33.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,11 +46,11 @@
46
46
  "types": "./build/index.d.ts",
47
47
  "dependencies": {
48
48
  "@automattic/jetpack-base-styles": "^1.0.1",
49
- "@automattic/jetpack-components": "^1.1.6",
50
- "@automattic/jetpack-connection": "^1.2.6",
49
+ "@automattic/jetpack-components": "^1.1.7",
50
+ "@automattic/jetpack-connection": "^1.2.7",
51
51
  "@automattic/jetpack-script-data": "^0.4.4",
52
52
  "@automattic/jetpack-explat": "workspace:*",
53
- "@automattic/jetpack-shared-extension-utils": "^1.2.1",
53
+ "@automattic/jetpack-shared-extension-utils": "^1.2.2",
54
54
  "@microsoft/fetch-event-source": "2.0.1",
55
55
  "@types/jest": "30.0.0",
56
56
  "@types/react": "18.3.23",
@@ -2,6 +2,10 @@
2
2
  * External dependencies
3
3
  */
4
4
  import apiFetchMod from '@wordpress/api-fetch';
5
+ /**
6
+ * Types
7
+ */
8
+ import type { APIFetchOptions } from '@wordpress/api-fetch';
5
9
 
6
10
  // @wordpress/api-fetch (as of 6.47.0) declares itself in such a way that tsc and node see the function at apiFetchMod.default
7
11
  // while some other environments (including code running inside WordPress itself) see it at apiFetch.
@@ -11,4 +15,10 @@ const apiFetch = 'default' in apiFetchMod ? apiFetchMod.default : apiFetchMod;
11
15
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
12
16
  type ApiFetchType = typeof apiFetch extends Function ? typeof apiFetch : typeof apiFetchMod;
13
17
 
14
- export default apiFetch as ApiFetchType;
18
+ type AugmentedAPIFetchOptions = APIFetchOptions & {
19
+ global?: boolean;
20
+ };
21
+
22
+ type AugmentedApiFetchType = ( options: AugmentedAPIFetchOptions ) => ReturnType< ApiFetchType >;
23
+
24
+ export default apiFetch as AugmentedApiFetchType;
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { initializeExPlat, loadExperimentAssignmentWithAuth } from '@automattic/jetpack-explat';
4
+ import { initializeExPlat, createExPlatClient } from '@automattic/jetpack-explat';
5
5
  import { select } from '@wordpress/data';
6
+ import { addQueryArgs } from '@wordpress/url';
6
7
  import debugFactory from 'debug';
7
-
8
- const debug = debugFactory( 'ai-client:chrome-ai-availability' );
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import apiFetch from '../api-fetch/index.ts';
9
12
 
10
13
  /**
11
14
  * Types
@@ -21,6 +24,8 @@ type PlansSelect = {
21
24
  };
22
25
  };
23
26
 
27
+ const debug = debugFactory( 'ai-client:chrome-ai-availability' );
28
+
24
29
  /**
25
30
  * Get the AI Assistant feature.
26
31
  *
@@ -31,6 +36,40 @@ function getAiAssistantFeature() {
31
36
  return getFeature();
32
37
  }
33
38
 
39
+ /**
40
+ * Fetch an experiment assignment.
41
+ *
42
+ * @param {boolean} asConnectedUser - Whether the user is connected.
43
+ * @return {Function} A function that fetches an experiment assignment.
44
+ */
45
+ const fetchExperimentAssignmentWithConnectedUser = async ( {
46
+ experimentName,
47
+ }: {
48
+ experimentName: string;
49
+ } ): Promise< unknown > => {
50
+ const params = {
51
+ experiment_name: experimentName,
52
+ anon_id: undefined,
53
+ as_connected_user: true,
54
+ };
55
+
56
+ debug( 'params', params );
57
+
58
+ const assignmentsRequestUrl = addQueryArgs(
59
+ 'https://public-api.wordpress.com/wpcom/v2/experiments/0.1.0/assignments/jetpack',
60
+ params
61
+ );
62
+
63
+ debug( 'assignmentsRequestUrl', assignmentsRequestUrl );
64
+
65
+ return apiFetch( {
66
+ url: assignmentsRequestUrl,
67
+ credentials: 'include',
68
+ mode: 'cors',
69
+ global: true,
70
+ } );
71
+ };
72
+
34
73
  /**
35
74
  * Check if Chrome AI can be enabled.
36
75
  *
@@ -46,7 +85,13 @@ export async function isChromeAIAvailable() {
46
85
  }
47
86
 
48
87
  initializeExPlat();
49
- debug( 'initialized explat' );
88
+
89
+ const { loadExperimentAssignment: loadExperimentAssignmentWithAuth } = createExPlatClient( {
90
+ fetchExperimentAssignment: fetchExperimentAssignmentWithConnectedUser,
91
+ getAnonId: async () => null,
92
+ logError: debug,
93
+ isDevelopmentMode: false,
94
+ } );
50
95
 
51
96
  const { variationName } = await loadExperimentAssignmentWithAuth(
52
97
  'calypso_jetpack_ai_gemini_api_202503_v1'
package/src/jwt/index.ts CHANGED
@@ -70,7 +70,7 @@ export default async function requestJwt( {
70
70
 
71
71
  const isSimple = isSimpleSite();
72
72
  if ( ! isSimple ) {
73
- data = await apiFetch( {
73
+ data = ( await apiFetch( {
74
74
  /*
75
75
  * This endpoint is registered in the Jetpack plugin.
76
76
  * Provably we should move it to another package, but for now it's here.
@@ -82,12 +82,12 @@ export default async function requestJwt( {
82
82
  'X-WP-Nonce': apiNonce,
83
83
  },
84
84
  method: 'POST',
85
- } );
85
+ } ) ) as TokenDataEndpointResponseProps;
86
86
  } else {
87
- data = await apiFetch( {
87
+ data = ( await apiFetch( {
88
88
  path: '/wpcom/v2/sites/' + siteId + '/jetpack-openai-query/jwt',
89
89
  method: 'POST',
90
- } );
90
+ } ) ) as TokenDataEndpointResponseProps;
91
91
  }
92
92
 
93
93
  const newTokenData = {
@@ -24,7 +24,7 @@ export default async function wpcomLimitedRequest< T >( params: object ): Promis
24
24
  throw new Error( 'Too many requests' );
25
25
  }
26
26
 
27
- return apiFetch< T >( params ).finally( () => {
27
+ return apiFetch( params ).finally( () => {
28
28
  concurrentCounter -= 1;
29
- } );
29
+ } ) as Promise< T >;
30
30
  }