@automattic/jetpack-ai-client 0.1.2 → 0.1.3
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 +20 -5
- package/package.json +10 -10
- package/src/ask-question/index.ts +0 -4
- package/src/components/ai-control/Readme.md +2 -2
- package/src/components/ai-control/index.tsx +58 -52
- package/src/components/ai-control/message.tsx +86 -0
- package/src/components/ai-control/style.scss +49 -26
- package/src/data-flow/use-ai-context.ts +2 -2
- package/src/hooks/use-ai-suggestions/index.ts +4 -4
- package/src/suggestions-event-source/index.ts +18 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,15 +5,29 @@ 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.1.3] - 2023-08-09
|
|
9
|
+
### Added
|
|
10
|
+
- AI Client: Introduce disabled prop in AI Control. [#32326]
|
|
11
|
+
- AI Control: Add guideline message. [#32358]
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- AI Client: handle token fetching errors by dispatching an event from the SuggestionsEventSource class. [#32350]
|
|
15
|
+
- AI Client: tweak layout and styles to make AI Control mobile friendly. [#32362]
|
|
16
|
+
- AI Control: clean up props. [#32360]
|
|
17
|
+
- Updated package dependencies. [#32166]
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- AI Client: fix TS type definition issue [#32330]
|
|
21
|
+
|
|
8
22
|
## [0.1.2] - 2023-08-07
|
|
9
23
|
### Added
|
|
10
|
-
- AI Assistant:
|
|
24
|
+
- AI Assistant: Add options parameter to request function on useAiSuggestions hook [#32198]
|
|
11
25
|
- AI Client: add @wordpress/compose dependency [#32228]
|
|
12
|
-
- AI Client:
|
|
13
|
-
- AI Client:
|
|
26
|
+
- AI Client: Add clear button in AI Control component [#32274]
|
|
27
|
+
- AI Client: Add keyboard shortcut to AIControl [#32239]
|
|
14
28
|
- AI Client: add onError() response support [#32223]
|
|
15
|
-
- AI Client:
|
|
16
|
-
- AI Client:
|
|
29
|
+
- AI Client: Export types [#32209]
|
|
30
|
+
- AI Client: Start supporting request options on requestSuggestion callback. [#32303]
|
|
17
31
|
- AI Control: introduce AiStatusIndicator component [#32258]
|
|
18
32
|
|
|
19
33
|
### Changed
|
|
@@ -54,5 +68,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
54
68
|
- Updated package dependencies. [#31659]
|
|
55
69
|
- Updated package dependencies. [#31785]
|
|
56
70
|
|
|
71
|
+
[0.1.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.2...v0.1.3
|
|
57
72
|
[0.1.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.1...v0.1.2
|
|
58
73
|
[0.1.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.1.0...v0.1.1
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@automattic/jetpack-ai-client",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
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": {
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@automattic/jetpack-connection": "workspace:*",
|
|
36
|
-
"@automattic/jetpack-shared-extension-utils": "^0.11.
|
|
36
|
+
"@automattic/jetpack-shared-extension-utils": "^0.11.1",
|
|
37
37
|
"@microsoft/fetch-event-source": "2.0.1",
|
|
38
|
-
"@wordpress/api-fetch": "6.
|
|
39
|
-
"@wordpress/block-editor": "12.
|
|
40
|
-
"@wordpress/components": "25.
|
|
41
|
-
"@wordpress/compose": "6.
|
|
42
|
-
"@wordpress/data": "9.
|
|
43
|
-
"@wordpress/element": "5.
|
|
44
|
-
"@wordpress/i18n": "4.
|
|
45
|
-
"@wordpress/icons": "9.
|
|
38
|
+
"@wordpress/api-fetch": "6.35.0",
|
|
39
|
+
"@wordpress/block-editor": "12.6.0",
|
|
40
|
+
"@wordpress/components": "25.4.0",
|
|
41
|
+
"@wordpress/compose": "6.15.0",
|
|
42
|
+
"@wordpress/data": "9.8.0",
|
|
43
|
+
"@wordpress/element": "5.15.0",
|
|
44
|
+
"@wordpress/i18n": "4.38.0",
|
|
45
|
+
"@wordpress/icons": "9.29.0",
|
|
46
46
|
"classnames": "2.3.2",
|
|
47
47
|
"debug": "4.3.4",
|
|
48
48
|
"react": "18.2.0",
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
4
|
import debugFactory from 'debug';
|
|
5
|
-
import requestJwt from '../jwt';
|
|
6
5
|
import SuggestionsEventSource from '../suggestions-event-source';
|
|
7
6
|
/*
|
|
8
7
|
* Types & constants
|
|
@@ -62,11 +61,8 @@ export default async function askQuestion(
|
|
|
62
61
|
): Promise< SuggestionsEventSource > {
|
|
63
62
|
debug( 'Asking question: %o. options: %o', question, { postId, fromCache, feature, functions } );
|
|
64
63
|
|
|
65
|
-
const { token } = await requestJwt();
|
|
66
|
-
|
|
67
64
|
return new SuggestionsEventSource( {
|
|
68
65
|
question,
|
|
69
|
-
token,
|
|
70
66
|
options: { postId, feature, fromCache, functions },
|
|
71
67
|
} );
|
|
72
68
|
}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
#### Properties
|
|
4
4
|
|
|
5
|
-
- `
|
|
5
|
+
- `disabled` (**boolean**) (Optional): Disables the ai control. Default value is `false`.
|
|
6
6
|
- `value` (**string**): Current input value. Default value is `''`.
|
|
7
7
|
- `placeholder` (**string**) (Optional): Placeholder text for the input field. Default value is `''`.
|
|
8
8
|
- `showAccept` (**boolean**) (Optional): Determines if the accept button is shown. Default value is `false`.
|
|
9
9
|
- `acceptLabel` (**string**) (Optional): Label text for the accept button. Default value is `'Accept'`.
|
|
10
10
|
- `showButtonsLabel` (**boolean**) (Optional): Determines if button labels are shown. Default value is `true`.
|
|
11
11
|
- `isOpaque` (**boolean**) (Optional): Controls the opacity of the component. Default value is `false`.
|
|
12
|
-
- `
|
|
12
|
+
- `state` (**RequestingStateProp**) (Optional): Determines the state of the component. Default value is `'init'`.
|
|
13
13
|
- `onChange` (**Function**) (Optional): Handler for input change. Default action is no operation.
|
|
14
14
|
- `onSend` (**Function**) (Optional): Handler to send a request. Default action is no operation.
|
|
15
15
|
- `onStop` (**Function**) (Optional): Handler to stop a request. Default action is no operation.
|
|
@@ -13,6 +13,7 @@ import classNames from 'classnames';
|
|
|
13
13
|
*/
|
|
14
14
|
import './style.scss';
|
|
15
15
|
import AiStatusIndicator from '../ai-status-indicator';
|
|
16
|
+
import { GuidelineMessage } from './message';
|
|
16
17
|
/**
|
|
17
18
|
* Types
|
|
18
19
|
*/
|
|
@@ -25,48 +26,50 @@ const noop = () => {};
|
|
|
25
26
|
* AI Control component.
|
|
26
27
|
*
|
|
27
28
|
* @param {object} props - component props
|
|
28
|
-
* @param {boolean} props.
|
|
29
|
+
* @param {boolean} props.disabled - is disabled
|
|
29
30
|
* @param {string} props.value - input value
|
|
30
31
|
* @param {string} props.placeholder - input placeholder
|
|
31
32
|
* @param {boolean} props.showAccept - show accept button
|
|
32
33
|
* @param {string} props.acceptLabel - accept button label
|
|
33
34
|
* @param {boolean} props.showButtonsLabel - show buttons label
|
|
34
35
|
* @param {boolean} props.isOpaque - is opaque
|
|
36
|
+
* @param {string} props.state - requesting state
|
|
35
37
|
* @param {Function} props.onChange - input change handler
|
|
36
38
|
* @param {Function} props.onSend - send request handler
|
|
37
39
|
* @param {Function} props.onStop - stop request handler
|
|
38
40
|
* @param {Function} props.onAccept - accept handler
|
|
39
|
-
* @param {string} props.requestingState - requesting state
|
|
40
41
|
* @returns {object} - AI Control component
|
|
41
42
|
*/
|
|
42
43
|
export default function AIControl( {
|
|
43
|
-
|
|
44
|
+
disabled = false,
|
|
44
45
|
value = '',
|
|
45
46
|
placeholder = '',
|
|
46
47
|
showAccept = false,
|
|
47
48
|
acceptLabel = __( 'Accept', 'jetpack-ai-client' ),
|
|
48
49
|
showButtonsLabel = true,
|
|
49
50
|
isOpaque = false,
|
|
50
|
-
|
|
51
|
+
state = 'init',
|
|
51
52
|
onChange = noop,
|
|
52
53
|
onSend = noop,
|
|
53
54
|
onStop = noop,
|
|
54
55
|
onAccept = noop,
|
|
55
56
|
}: {
|
|
56
|
-
|
|
57
|
+
disabled?: boolean;
|
|
57
58
|
value: string;
|
|
58
59
|
placeholder?: string;
|
|
59
60
|
showAccept?: boolean;
|
|
60
61
|
acceptLabel?: string;
|
|
61
62
|
showButtonsLabel?: boolean;
|
|
62
63
|
isOpaque?: boolean;
|
|
63
|
-
|
|
64
|
+
state?: RequestingStateProp;
|
|
64
65
|
onChange?: ( newValue: string ) => void;
|
|
65
66
|
onSend?: ( currentValue: string ) => void;
|
|
66
67
|
onStop?: () => void;
|
|
67
68
|
onAccept?: () => void;
|
|
68
69
|
} ) {
|
|
69
70
|
const promptUserInputRef = useRef( null );
|
|
71
|
+
const loading = state === 'requesting' || state === 'suggesting';
|
|
72
|
+
const showGuideLine = ! ( loading || disabled || value?.length || isOpaque );
|
|
70
73
|
|
|
71
74
|
useKeyboardShortcut(
|
|
72
75
|
'mod+enter',
|
|
@@ -91,6 +94,10 @@ export default function AIControl( {
|
|
|
91
94
|
}
|
|
92
95
|
);
|
|
93
96
|
|
|
97
|
+
const actionButtonClasses = classNames( 'jetpack-components-ai-control__controls-prompt_button', {
|
|
98
|
+
'has-label': showButtonsLabel,
|
|
99
|
+
} );
|
|
100
|
+
|
|
94
101
|
return (
|
|
95
102
|
<div className="jetpack-components-ai-control__container">
|
|
96
103
|
<div
|
|
@@ -98,7 +105,7 @@ export default function AIControl( {
|
|
|
98
105
|
'is-opaque': isOpaque,
|
|
99
106
|
} ) }
|
|
100
107
|
>
|
|
101
|
-
<AiStatusIndicator state={
|
|
108
|
+
<AiStatusIndicator state={ state } />
|
|
102
109
|
|
|
103
110
|
<div className="jetpack-components-ai-control__input-wrapper">
|
|
104
111
|
<PlainText
|
|
@@ -106,60 +113,59 @@ export default function AIControl( {
|
|
|
106
113
|
onChange={ onChange }
|
|
107
114
|
placeholder={ placeholder }
|
|
108
115
|
className="jetpack-components-ai-control__input"
|
|
109
|
-
disabled={ loading }
|
|
116
|
+
disabled={ loading || disabled }
|
|
110
117
|
ref={ promptUserInputRef }
|
|
111
118
|
/>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
{ value?.length > 0 && (
|
|
122
|
+
<Button
|
|
123
|
+
icon={ closeSmall }
|
|
124
|
+
className="jetpack-components-ai-control__clear"
|
|
125
|
+
onClick={ () => onChange( '' ) }
|
|
126
|
+
/>
|
|
127
|
+
) }
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
className=
|
|
117
|
-
onClick={ () =>
|
|
118
|
-
|
|
129
|
+
<div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
|
|
130
|
+
{ ! loading ? (
|
|
131
|
+
<Button
|
|
132
|
+
className={ actionButtonClasses }
|
|
133
|
+
onClick={ () => onSend( value ) }
|
|
134
|
+
isSmall={ true }
|
|
135
|
+
disabled={ ! value?.length || disabled }
|
|
136
|
+
label={ __( 'Send request', 'jetpack-ai-client' ) }
|
|
137
|
+
>
|
|
138
|
+
<Icon icon={ arrowUp } />
|
|
139
|
+
{ showButtonsLabel && __( 'Send', 'jetpack-ai-client' ) }
|
|
140
|
+
</Button>
|
|
141
|
+
) : (
|
|
142
|
+
<Button
|
|
143
|
+
className={ actionButtonClasses }
|
|
144
|
+
onClick={ onStop }
|
|
145
|
+
isSmall={ true }
|
|
146
|
+
label={ __( 'Stop request', 'jetpack-ai-client' ) }
|
|
147
|
+
>
|
|
148
|
+
<Icon icon={ closeSmall } />
|
|
149
|
+
{ showButtonsLabel && __( 'Stop', 'jetpack-ai-client' ) }
|
|
150
|
+
</Button>
|
|
119
151
|
) }
|
|
120
152
|
</div>
|
|
121
153
|
|
|
122
|
-
|
|
154
|
+
{ showAccept && (
|
|
123
155
|
<div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
{ showButtonsLabel && __( 'Send', 'jetpack-ai-client' ) }
|
|
134
|
-
</Button>
|
|
135
|
-
) : (
|
|
136
|
-
<Button
|
|
137
|
-
className="jetpack-components-ai-control__controls-prompt_button"
|
|
138
|
-
onClick={ onStop }
|
|
139
|
-
isSmall={ true }
|
|
140
|
-
label={ __( 'Stop request', 'jetpack-ai-client' ) }
|
|
141
|
-
>
|
|
142
|
-
<Icon icon={ closeSmall } />
|
|
143
|
-
{ showButtonsLabel && __( 'Stop', 'jetpack-ai-client' ) }
|
|
144
|
-
</Button>
|
|
145
|
-
) }
|
|
156
|
+
<Button
|
|
157
|
+
className={ actionButtonClasses }
|
|
158
|
+
onClick={ onAccept }
|
|
159
|
+
isSmall={ true }
|
|
160
|
+
label={ acceptLabel }
|
|
161
|
+
>
|
|
162
|
+
<Icon icon={ check } />
|
|
163
|
+
{ showButtonsLabel && acceptLabel }
|
|
164
|
+
</Button>
|
|
146
165
|
</div>
|
|
147
|
-
|
|
148
|
-
{ showAccept && (
|
|
149
|
-
<div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
|
|
150
|
-
<Button
|
|
151
|
-
className="jetpack-components-ai-control__controls-prompt_button"
|
|
152
|
-
onClick={ onAccept }
|
|
153
|
-
isSmall={ true }
|
|
154
|
-
label={ acceptLabel }
|
|
155
|
-
>
|
|
156
|
-
<Icon icon={ check } />
|
|
157
|
-
{ acceptLabel }
|
|
158
|
-
</Button>
|
|
159
|
-
</div>
|
|
160
|
-
) }
|
|
161
|
-
</div>
|
|
166
|
+
) }
|
|
162
167
|
</div>
|
|
168
|
+
{ showGuideLine && <GuidelineMessage /> }
|
|
163
169
|
</div>
|
|
164
170
|
);
|
|
165
171
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { ExternalLink } from '@wordpress/components';
|
|
5
|
+
import { createInterpolateElement } from '@wordpress/element';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
import {
|
|
8
|
+
Icon,
|
|
9
|
+
warning,
|
|
10
|
+
info,
|
|
11
|
+
cancelCircleFilled as error,
|
|
12
|
+
check as success,
|
|
13
|
+
} from '@wordpress/icons';
|
|
14
|
+
/**
|
|
15
|
+
* Types
|
|
16
|
+
*/
|
|
17
|
+
import type React from 'react';
|
|
18
|
+
|
|
19
|
+
import './style.scss';
|
|
20
|
+
|
|
21
|
+
export const MESSAGE_SEVERITY_WARNING = 'warning';
|
|
22
|
+
export const MESSAGE_SEVERITY_ERROR = 'error';
|
|
23
|
+
export const MESSAGE_SEVERITY_SUCCESS = 'success';
|
|
24
|
+
export const MESSAGE_SEVERITY_INFO = 'info';
|
|
25
|
+
|
|
26
|
+
const messageSeverityTypes = [
|
|
27
|
+
MESSAGE_SEVERITY_WARNING,
|
|
28
|
+
MESSAGE_SEVERITY_ERROR,
|
|
29
|
+
MESSAGE_SEVERITY_SUCCESS,
|
|
30
|
+
MESSAGE_SEVERITY_INFO,
|
|
31
|
+
] as const;
|
|
32
|
+
|
|
33
|
+
export type MessageSeverityProp = ( typeof messageSeverityTypes )[ number ] | null;
|
|
34
|
+
|
|
35
|
+
export type MessageProps = {
|
|
36
|
+
icon?: React.ReactNode;
|
|
37
|
+
children: React.ReactNode;
|
|
38
|
+
severity: MessageSeverityProp;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const messageIconsMap = {
|
|
42
|
+
[ MESSAGE_SEVERITY_WARNING ]: warning,
|
|
43
|
+
[ MESSAGE_SEVERITY_ERROR ]: error,
|
|
44
|
+
[ MESSAGE_SEVERITY_SUCCESS ]: success,
|
|
45
|
+
[ MESSAGE_SEVERITY_INFO ]: info,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* React component to render a block message.
|
|
50
|
+
*
|
|
51
|
+
* @param {MessageProps} props - Component props.
|
|
52
|
+
* @returns {React.ReactElement } Banner component.
|
|
53
|
+
*/
|
|
54
|
+
export default function Message( {
|
|
55
|
+
severity = null,
|
|
56
|
+
icon = null,
|
|
57
|
+
children,
|
|
58
|
+
}: MessageProps ): React.ReactElement {
|
|
59
|
+
return (
|
|
60
|
+
<div className="jetpack-ai-assistant__message">
|
|
61
|
+
{ ( severity || icon ) && <Icon icon={ messageIconsMap[ severity ] || icon } /> }
|
|
62
|
+
<div className="jetpack-ai-assistant__message-content">{ children }</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* React component to render a guideline message.
|
|
69
|
+
*
|
|
70
|
+
* @returns {React.ReactElement } - Message component.
|
|
71
|
+
*/
|
|
72
|
+
export function GuidelineMessage(): React.ReactElement {
|
|
73
|
+
return (
|
|
74
|
+
<Message severity={ MESSAGE_SEVERITY_INFO }>
|
|
75
|
+
{ createInterpolateElement(
|
|
76
|
+
__(
|
|
77
|
+
'AI-generated content could be inaccurate or biased. <link>Learn more</link>',
|
|
78
|
+
'jetpack-ai-client'
|
|
79
|
+
),
|
|
80
|
+
{
|
|
81
|
+
link: <ExternalLink href="https://automattic.com/ai-guidelines" />,
|
|
82
|
+
}
|
|
83
|
+
) }
|
|
84
|
+
</Message>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// AI CONTROL
|
|
2
|
+
|
|
1
3
|
.jetpack-components-ai-control__container {
|
|
2
4
|
color: var( --jp-gray-80 );
|
|
3
5
|
background-color: var( --jp-white );
|
|
@@ -23,26 +25,11 @@
|
|
|
23
25
|
flex-grow: 1;
|
|
24
26
|
width: 100%;
|
|
25
27
|
|
|
26
|
-
.jetpack-components-ai-control__clear {
|
|
27
|
-
position: absolute;
|
|
28
|
-
right: 8px;
|
|
29
|
-
top: calc( 50% - 12px );
|
|
30
|
-
border-radius: 50%;
|
|
31
|
-
background-color: black;
|
|
32
|
-
opacity: 0.2;
|
|
33
|
-
fill: white;
|
|
34
|
-
cursor: pointer;
|
|
35
|
-
|
|
36
|
-
&:hover {
|
|
37
|
-
opacity: 0.4;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
28
|
textarea.jetpack-components-ai-control__input {
|
|
42
29
|
width: 100%;
|
|
43
30
|
min-height: 20px;
|
|
44
31
|
border-radius: 2px;
|
|
45
|
-
padding: 6px
|
|
32
|
+
padding: 6px 8px;
|
|
46
33
|
|
|
47
34
|
resize: none !important;
|
|
48
35
|
border: none;
|
|
@@ -72,6 +59,21 @@
|
|
|
72
59
|
}
|
|
73
60
|
}
|
|
74
61
|
|
|
62
|
+
.jetpack-components-ai-control__clear.components-button.has-icon {
|
|
63
|
+
width: 24px;
|
|
64
|
+
min-width: 24px;
|
|
65
|
+
height: 24px;
|
|
66
|
+
padding: 0;
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
background-color: black;
|
|
69
|
+
opacity: 0.2;
|
|
70
|
+
color: white;
|
|
71
|
+
|
|
72
|
+
&:hover {
|
|
73
|
+
opacity: 0.4;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
75
77
|
.jetpack-components-ai-controlton__icon {
|
|
76
78
|
flex-shrink: 0;
|
|
77
79
|
display: flex;
|
|
@@ -94,11 +96,6 @@
|
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
.jetpack-components-ai-control__controls {
|
|
98
|
-
display: flex;
|
|
99
|
-
align-items: center;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
99
|
.jetpack-components-ai-control__controls-prompt_button_wrapper {
|
|
103
100
|
text-transform: uppercase;
|
|
104
101
|
font-size: 11px;
|
|
@@ -108,16 +105,16 @@
|
|
|
108
105
|
white-space: nowrap;
|
|
109
106
|
display: flex;
|
|
110
107
|
align-items: center;
|
|
108
|
+
|
|
109
|
+
.components-button.is-small:not(.has-label) {
|
|
110
|
+
padding: 0;
|
|
111
|
+
}
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
.jetpack-components-ai-control__controls-prompt_button {
|
|
114
115
|
color: var( --jp-gray-80 );
|
|
115
116
|
text-transform: uppercase;
|
|
116
117
|
|
|
117
|
-
> SVG {
|
|
118
|
-
margin-right: 4px;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
118
|
&:hover,
|
|
122
119
|
&:active {
|
|
123
120
|
color: var( --wp-components-color-accent, var( --wp-admin-theme-color ) );
|
|
@@ -127,4 +124,30 @@
|
|
|
127
124
|
opacity: 0.6;
|
|
128
125
|
cursor: not-allowed;
|
|
129
126
|
}
|
|
130
|
-
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// MESSAGE
|
|
130
|
+
|
|
131
|
+
.jetpack-ai-assistant__message {
|
|
132
|
+
display: flex;
|
|
133
|
+
line-height: 28px;
|
|
134
|
+
font-size: 12px;
|
|
135
|
+
align-self: center;
|
|
136
|
+
align-items: center;
|
|
137
|
+
background-color: var( --jp-white-off );
|
|
138
|
+
padding: 0 12px;
|
|
139
|
+
|
|
140
|
+
> svg {
|
|
141
|
+
fill: var( --jp-gray-40 );
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.jetpack-ai-assistant__message-content {
|
|
145
|
+
flex-grow: 2;
|
|
146
|
+
margin: 0 8px;
|
|
147
|
+
color: var( --jp-gray-70 );
|
|
148
|
+
|
|
149
|
+
.components-external-link {
|
|
150
|
+
color: var( --jp-gray-50 );
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -5,7 +5,7 @@ import { useCallback, useContext, useEffect } from '@wordpress/element';
|
|
|
5
5
|
/**
|
|
6
6
|
* Internal dependencies
|
|
7
7
|
*/
|
|
8
|
-
import { ERROR_RESPONSE } from '../types';
|
|
8
|
+
import { ERROR_RESPONSE, RequestingErrorProps } from '../types';
|
|
9
9
|
import { AiDataContext } from '.';
|
|
10
10
|
/**
|
|
11
11
|
* Types & constants
|
|
@@ -32,7 +32,7 @@ export type UseAiContextOptions = {
|
|
|
32
32
|
/*
|
|
33
33
|
* onError callback.
|
|
34
34
|
*/
|
|
35
|
-
onError?: ( error:
|
|
35
|
+
onError?: ( error: RequestingErrorProps ) => void;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -234,7 +234,7 @@ export default function useAiSuggestions( {
|
|
|
234
234
|
|
|
235
235
|
const handleModerationError = useCallback( () => handleError( ERROR_MODERATION ), [] );
|
|
236
236
|
|
|
237
|
-
const
|
|
237
|
+
const handleNetworkError = useCallback( () => handleError( ERROR_NETWORK ), [] );
|
|
238
238
|
|
|
239
239
|
/**
|
|
240
240
|
* Request handler.
|
|
@@ -278,7 +278,7 @@ export default function useAiSuggestions( {
|
|
|
278
278
|
eventSource.addEventListener( ERROR_UNCLEAR_PROMPT, handleUnclearPromptError );
|
|
279
279
|
eventSource.addEventListener( ERROR_SERVICE_UNAVAILABLE, handleServiceUnavailableError );
|
|
280
280
|
eventSource.addEventListener( ERROR_MODERATION, handleModerationError );
|
|
281
|
-
eventSource.addEventListener( ERROR_NETWORK,
|
|
281
|
+
eventSource.addEventListener( ERROR_NETWORK, handleNetworkError );
|
|
282
282
|
|
|
283
283
|
eventSource.addEventListener( 'done', handleDone );
|
|
284
284
|
} catch ( e ) {
|
|
@@ -292,7 +292,7 @@ export default function useAiSuggestions( {
|
|
|
292
292
|
handleUnclearPromptError,
|
|
293
293
|
handleServiceUnavailableError,
|
|
294
294
|
handleModerationError,
|
|
295
|
-
|
|
295
|
+
handleNetworkError,
|
|
296
296
|
handleSuggestion,
|
|
297
297
|
]
|
|
298
298
|
);
|
|
@@ -327,7 +327,7 @@ export default function useAiSuggestions( {
|
|
|
327
327
|
eventSource.removeEventListener( ERROR_UNCLEAR_PROMPT, handleUnclearPromptError );
|
|
328
328
|
eventSource.removeEventListener( ERROR_SERVICE_UNAVAILABLE, handleServiceUnavailableError );
|
|
329
329
|
eventSource.removeEventListener( ERROR_MODERATION, handleModerationError );
|
|
330
|
-
eventSource.removeEventListener( ERROR_NETWORK,
|
|
330
|
+
eventSource.removeEventListener( ERROR_NETWORK, handleNetworkError );
|
|
331
331
|
|
|
332
332
|
eventSource.removeEventListener( 'done', handleDone );
|
|
333
333
|
};
|
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source';
|
|
5
5
|
import debugFactory from 'debug';
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { getErrorData } from '../hooks/use-ai-suggestions';
|
|
10
|
+
import requestJwt from '../jwt';
|
|
6
11
|
/*
|
|
7
12
|
* Types & constants
|
|
8
13
|
*/
|
|
9
|
-
import { getErrorData } from '../hooks/use-ai-suggestions';
|
|
10
14
|
import {
|
|
11
15
|
ERROR_MODERATION,
|
|
12
16
|
ERROR_NETWORK,
|
|
@@ -20,7 +24,7 @@ import type { PromptMessagesProp, PromptProp, SuggestionErrorCode } from '../typ
|
|
|
20
24
|
type SuggestionsEventSourceConstructorArgs = {
|
|
21
25
|
url?: string;
|
|
22
26
|
question: PromptProp;
|
|
23
|
-
token
|
|
27
|
+
token?: string;
|
|
24
28
|
options?: {
|
|
25
29
|
postId?: number;
|
|
26
30
|
feature?: 'ai-assistant-experimental' | string | undefined;
|
|
@@ -81,6 +85,18 @@ export default class SuggestionsEventSource extends EventTarget {
|
|
|
81
85
|
token,
|
|
82
86
|
options = {},
|
|
83
87
|
}: SuggestionsEventSourceConstructorArgs ) {
|
|
88
|
+
// If the token is not provided, try to get one
|
|
89
|
+
if ( ! token ) {
|
|
90
|
+
try {
|
|
91
|
+
debug( 'Token was not provided, requesting one...' );
|
|
92
|
+
token = ( await requestJwt() ).token;
|
|
93
|
+
} catch ( err ) {
|
|
94
|
+
this.processErrorEvent( err );
|
|
95
|
+
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
84
100
|
const bodyData: {
|
|
85
101
|
post_id?: number;
|
|
86
102
|
messages?: PromptMessagesProp;
|