@sanity/assist 4.0.2 → 4.2.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/README.md +25 -0
- package/dist/index.d.mts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.esm.js +79 -38
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +79 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/ImageContext.tsx +4 -4
- package/src/helpers/styleguide.ts +24 -0
- package/src/helpers/typeUtils.ts +13 -3
- package/src/plugin.tsx +4 -5
- package/src/schemas/typeDefExtensions.ts +12 -1
- package/src/translate/FieldTranslationProvider.tsx +14 -3
- package/src/translate/translateActions.tsx +12 -4
- package/src/translate/types.ts +18 -2
- package/src/useApiClient.ts +8 -5
package/package.json
CHANGED
|
@@ -40,7 +40,7 @@ export function ImageContextProvider(props: InputProps) {
|
|
|
40
40
|
if (
|
|
41
41
|
assetRef &&
|
|
42
42
|
assistableDocumentId &&
|
|
43
|
-
descriptionField &&
|
|
43
|
+
descriptionField?.updateOnImageChange &&
|
|
44
44
|
assetRef !== assetRefState &&
|
|
45
45
|
!isSyncing &&
|
|
46
46
|
!isShowingOlderRevision &&
|
|
@@ -49,7 +49,7 @@ export function ImageContextProvider(props: InputProps) {
|
|
|
49
49
|
setAssetRefState(assetRef)
|
|
50
50
|
if (canUseAssist(status)) {
|
|
51
51
|
generateCaption({
|
|
52
|
-
path: pathToString([...path, descriptionField]),
|
|
52
|
+
path: pathToString([...path, descriptionField.path]),
|
|
53
53
|
documentId: assistableDocumentId,
|
|
54
54
|
})
|
|
55
55
|
}
|
|
@@ -71,8 +71,8 @@ export function ImageContextProvider(props: InputProps) {
|
|
|
71
71
|
const descriptionField = getDescriptionFieldOption(schemaType)
|
|
72
72
|
const imageInstructionField = getImageInstructionFieldOption(schemaType)
|
|
73
73
|
return {
|
|
74
|
-
imageDescriptionPath: descriptionField
|
|
75
|
-
? pathToString([...path, descriptionField])
|
|
74
|
+
imageDescriptionPath: descriptionField?.path
|
|
75
|
+
? pathToString([...path, descriptionField.path])
|
|
76
76
|
: undefined,
|
|
77
77
|
imageInstructionPath: imageInstructionField
|
|
78
78
|
? pathToString([...path, imageInstructionField])
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {packageName} from '../constants'
|
|
2
|
+
import {TranslateStyleguide, TranslateStyleguideContext} from '../translate/types'
|
|
3
|
+
|
|
4
|
+
export function validateStyleguide(styleguide: string | undefined) {
|
|
5
|
+
if (styleguide && styleguide.length > 2000) {
|
|
6
|
+
throw new Error(
|
|
7
|
+
`[${packageName}]: \`translate.styleguide\` value is too long. It must be 2000 characters or less, but was ${styleguide.length} characters`,
|
|
8
|
+
)
|
|
9
|
+
}
|
|
10
|
+
return styleguide
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createStyleGuideResolver(
|
|
14
|
+
styleguide: TranslateStyleguide | undefined,
|
|
15
|
+
context: TranslateStyleguideContext,
|
|
16
|
+
) {
|
|
17
|
+
return async () => {
|
|
18
|
+
if (typeof styleguide !== 'function') {
|
|
19
|
+
return styleguide
|
|
20
|
+
}
|
|
21
|
+
const styleguideResult = await styleguide(context)
|
|
22
|
+
return validateStyleguide(styleguideResult)
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/helpers/typeUtils.ts
CHANGED
|
@@ -18,13 +18,23 @@ export function isImage(schemaType: SchemaType) {
|
|
|
18
18
|
return isType(schemaType, 'image')
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export function getDescriptionFieldOption(
|
|
21
|
+
export function getDescriptionFieldOption(
|
|
22
|
+
schemaType: SchemaType | undefined,
|
|
23
|
+
): {path: string; updateOnImageChange: boolean} | undefined {
|
|
22
24
|
if (!schemaType) {
|
|
23
25
|
return undefined
|
|
24
26
|
}
|
|
25
27
|
const descriptionField = (schemaType.options as ImageOptions)?.aiAssist?.imageDescriptionField
|
|
26
|
-
if (descriptionField) {
|
|
27
|
-
return
|
|
28
|
+
if (typeof descriptionField === 'string') {
|
|
29
|
+
return {
|
|
30
|
+
path: descriptionField,
|
|
31
|
+
updateOnImageChange: true,
|
|
32
|
+
}
|
|
33
|
+
} else if (descriptionField) {
|
|
34
|
+
return {
|
|
35
|
+
path: descriptionField.path,
|
|
36
|
+
updateOnImageChange: descriptionField.updateOnImageChange ?? true,
|
|
37
|
+
}
|
|
28
38
|
}
|
|
29
39
|
return getDescriptionFieldOption(schemaType.type)
|
|
30
40
|
}
|
package/src/plugin.tsx
CHANGED
|
@@ -9,17 +9,18 @@ import {AssistInlineFormBlock} from './assistFormComponents/AssistInlineFormBloc
|
|
|
9
9
|
import {AssistItem} from './assistFormComponents/AssistItem'
|
|
10
10
|
import {assistInspector} from './assistInspector'
|
|
11
11
|
import {AssistLayout} from './assistLayout/AssistLayout'
|
|
12
|
+
import {AssistConfig} from './assistTypes'
|
|
12
13
|
import {ImageContextProvider} from './components/ImageContext'
|
|
13
14
|
import {SafeValueInput} from './components/SafeValueInput'
|
|
14
15
|
import {packageName} from './constants'
|
|
15
16
|
import {assistFieldActions} from './fieldActions/assistFieldActions'
|
|
16
17
|
import {isSchemaAssistEnabled} from './helpers/assistSupported'
|
|
18
|
+
import {validateStyleguide} from './helpers/styleguide'
|
|
17
19
|
import {isImage} from './helpers/typeUtils'
|
|
18
20
|
import {createAssistDocumentPresence} from './presence/AssistDocumentPresence'
|
|
19
21
|
import {schemaTypes} from './schemas'
|
|
20
22
|
import {TranslationConfig} from './translate/types'
|
|
21
23
|
import {assistDocumentTypeName, AssistPreset} from './types'
|
|
22
|
-
import {AssistConfig} from './assistTypes'
|
|
23
24
|
|
|
24
25
|
export interface AssistPluginConfig {
|
|
25
26
|
translate?: TranslationConfig
|
|
@@ -46,10 +47,8 @@ export const assist = definePlugin<AssistPluginConfig | void>((config) => {
|
|
|
46
47
|
const maxPathDepth = configWithDefaults.assist?.maxPathDepth
|
|
47
48
|
const temperature = configWithDefaults.assist?.temperature
|
|
48
49
|
|
|
49
|
-
if (styleguide
|
|
50
|
-
|
|
51
|
-
`[${packageName}]: \`translate.styleguide\` value is too long. It must be 2000 characters or less, was ${styleguide.length} characters`,
|
|
52
|
-
)
|
|
50
|
+
if (typeof styleguide === 'string') {
|
|
51
|
+
validateStyleguide(styleguide)
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
if (maxPathDepth !== undefined && (maxPathDepth < 1 || maxPathDepth > 12)) {
|
|
@@ -90,7 +90,18 @@ declare module 'sanity' {
|
|
|
90
90
|
* })
|
|
91
91
|
* ```
|
|
92
92
|
*/
|
|
93
|
-
imageDescriptionField?:
|
|
93
|
+
imageDescriptionField?:
|
|
94
|
+
| string
|
|
95
|
+
| {
|
|
96
|
+
path: string
|
|
97
|
+
/**
|
|
98
|
+
* When updateOnImageChange is true (or undefined), whenever the
|
|
99
|
+
* image asset changes, imageDescriptionField will be regenerated.
|
|
100
|
+
*
|
|
101
|
+
* default: true
|
|
102
|
+
* */
|
|
103
|
+
updateOnImageChange?: boolean
|
|
104
|
+
}
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
interface NumberOptions extends AssistOptions {}
|
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
|
|
20
20
|
import {useAiAssistanceConfig} from '../assistLayout/AiAssistanceConfigContext'
|
|
21
21
|
import type {ConditionalMemberState} from '../helpers/conditionalMembers'
|
|
22
|
-
import {
|
|
22
|
+
import {createStyleGuideResolver} from '../helpers/styleguide'
|
|
23
|
+
import {API_VERSION_WITH_EXTENDED_TYPES, useApiClient, useTranslate} from '../useApiClient'
|
|
23
24
|
import {getLanguageParams} from './getLanguageParams'
|
|
24
25
|
import {getPreferredToFieldLanguages, setPreferredToFieldLanguages} from './languageStore'
|
|
25
26
|
import {
|
|
@@ -67,6 +68,7 @@ function hasValuesToTranslate(
|
|
|
67
68
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
68
69
|
export function FieldTranslationProvider(props: PropsWithChildren<{}>) {
|
|
69
70
|
const {config: assistConfig} = useAiAssistanceConfig()
|
|
71
|
+
|
|
70
72
|
const apiClient = useApiClient(assistConfig.__customApiClient)
|
|
71
73
|
const styleguide = assistConfig.translate?.styleguide
|
|
72
74
|
const config = assistConfig.translate?.field
|
|
@@ -87,7 +89,9 @@ export function FieldTranslationProvider(props: PropsWithChildren<{}>) {
|
|
|
87
89
|
setLanguages(undefined)
|
|
88
90
|
setFieldTranslationParams(undefined)
|
|
89
91
|
}, [])
|
|
90
|
-
const languageClient = useClient({
|
|
92
|
+
const languageClient = useClient({
|
|
93
|
+
apiVersion: config?.apiVersion ?? API_VERSION_WITH_EXTENDED_TYPES,
|
|
94
|
+
})
|
|
91
95
|
const documentId = fieldTranslationParams?.document?._id
|
|
92
96
|
const id = useId()
|
|
93
97
|
|
|
@@ -195,7 +199,12 @@ export function FieldTranslationProvider(props: PropsWithChildren<{}>) {
|
|
|
195
199
|
runTranslate({
|
|
196
200
|
documentId,
|
|
197
201
|
translatePath,
|
|
198
|
-
styleguide,
|
|
202
|
+
styleguide: createStyleGuideResolver(styleguide, {
|
|
203
|
+
client: languageClient,
|
|
204
|
+
documentId,
|
|
205
|
+
schemaType: fieldTranslationParams?.documentSchema,
|
|
206
|
+
translatePath,
|
|
207
|
+
}),
|
|
199
208
|
fieldLanguageMap: fieldLanguageMaps.map((map) => ({
|
|
200
209
|
...map,
|
|
201
210
|
// eslint-disable-next-line max-nested-callbacks
|
|
@@ -214,6 +223,8 @@ export function FieldTranslationProvider(props: PropsWithChildren<{}>) {
|
|
|
214
223
|
toLanguages,
|
|
215
224
|
fieldTranslationParams?.translatePath,
|
|
216
225
|
fieldTranslationParams?.conditionalMembers,
|
|
226
|
+
fieldTranslationParams?.documentSchema,
|
|
227
|
+
languageClient,
|
|
217
228
|
])
|
|
218
229
|
|
|
219
230
|
const runButton = (
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import {TranslateIcon} from '@sanity/icons'
|
|
3
3
|
import {Box, Spinner} from '@sanity/ui'
|
|
4
4
|
import {useMemo, useRef} from 'react'
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
6
|
DocumentFieldAction,
|
|
7
7
|
DocumentFieldActionGroup,
|
|
8
8
|
DocumentFieldActionItem,
|
|
9
9
|
DocumentFieldActionProps,
|
|
10
10
|
ObjectSchemaType,
|
|
11
|
+
useClient,
|
|
11
12
|
} from 'sanity'
|
|
12
13
|
import {useDocumentPane} from 'sanity/structure'
|
|
13
14
|
|
|
@@ -15,8 +16,9 @@ import {useDraftDelayedTask} from '../assistDocument/RequestRunInstructionProvid
|
|
|
15
16
|
import {useAiAssistanceConfig} from '../assistLayout/AiAssistanceConfigContext'
|
|
16
17
|
import {isAssistSupported} from '../helpers/assistSupported'
|
|
17
18
|
import {getConditionalMembers} from '../helpers/conditionalMembers'
|
|
19
|
+
import {createStyleGuideResolver} from '../helpers/styleguide'
|
|
18
20
|
import type {AssistOptions} from '../schemas/typeDefExtensions'
|
|
19
|
-
import {useApiClient, useTranslate} from '../useApiClient'
|
|
21
|
+
import {API_VERSION_WITH_EXTENDED_TYPES, useApiClient, useTranslate} from '../useApiClient'
|
|
20
22
|
import {useFieldTranslation} from './FieldTranslationProvider'
|
|
21
23
|
|
|
22
24
|
function node(node: DocumentFieldActionItem | DocumentFieldActionGroup) {
|
|
@@ -32,7 +34,7 @@ export const translateActions: DocumentFieldAction = {
|
|
|
32
34
|
useAction(props: TranslateProps) {
|
|
33
35
|
const {config, status} = useAiAssistanceConfig()
|
|
34
36
|
const apiClient = useApiClient(config?.__customApiClient)
|
|
35
|
-
|
|
37
|
+
const client = useClient({apiVersion: API_VERSION_WITH_EXTENDED_TYPES})
|
|
36
38
|
const {
|
|
37
39
|
schemaType: fieldSchemaType,
|
|
38
40
|
path,
|
|
@@ -99,7 +101,11 @@ export const translateActions: DocumentFieldAction = {
|
|
|
99
101
|
translate({
|
|
100
102
|
languagePath,
|
|
101
103
|
translatePath: path,
|
|
102
|
-
styleguide,
|
|
104
|
+
styleguide: createStyleGuideResolver(styleguide, {
|
|
105
|
+
client,
|
|
106
|
+
documentId,
|
|
107
|
+
schemaType: documentSchemaType,
|
|
108
|
+
}),
|
|
103
109
|
documentId: documentId ?? '',
|
|
104
110
|
conditionalMembers: formStateRef.current
|
|
105
111
|
? getConditionalMembers(formStateRef.current)
|
|
@@ -118,6 +124,8 @@ export const translateActions: DocumentFieldAction = {
|
|
|
118
124
|
documentTranslationEnabled,
|
|
119
125
|
path,
|
|
120
126
|
readOnly,
|
|
127
|
+
client,
|
|
128
|
+
documentSchemaType,
|
|
121
129
|
])
|
|
122
130
|
const fieldTranslate = useFieldTranslation()
|
|
123
131
|
const openFieldTranslation = useDraftDelayedTask({
|
package/src/translate/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Path, SanityClient, SchemaType} from 'sanity'
|
|
1
|
+
import {ObjectSchemaType, Path, SanityClient, SchemaType} from 'sanity'
|
|
2
2
|
|
|
3
3
|
export interface Language {
|
|
4
4
|
id: string
|
|
@@ -163,6 +163,20 @@ export interface DocumentTranslationConfig {
|
|
|
163
163
|
documentTypes?: string[]
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
export interface TranslateStyleguideContext {
|
|
167
|
+
documentId: string
|
|
168
|
+
schemaType: ObjectSchemaType
|
|
169
|
+
client: SanityClient
|
|
170
|
+
/**
|
|
171
|
+
* Only provided for field translations
|
|
172
|
+
*/
|
|
173
|
+
translatePath?: Path
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export type TranslateStyleguide =
|
|
177
|
+
| string
|
|
178
|
+
| ((context: TranslateStyleguideContext) => Promise<string>)
|
|
179
|
+
|
|
166
180
|
export interface TranslationConfig {
|
|
167
181
|
/**
|
|
168
182
|
* Config for document types with fields in multiple languages in the same document.
|
|
@@ -176,6 +190,8 @@ export interface TranslationConfig {
|
|
|
176
190
|
* A "style guide" that can be used to provide guidance on how to translate content.
|
|
177
191
|
* Will be passed to the LLM - ergo this is only a guide and the model _may_ not
|
|
178
192
|
* always follow it to the letter.
|
|
193
|
+
*
|
|
194
|
+
* When providing a function, consider caching the results of any async operation; it will invoked every time translate runs
|
|
179
195
|
*/
|
|
180
|
-
styleguide?:
|
|
196
|
+
styleguide?: TranslateStyleguide
|
|
181
197
|
}
|
package/src/useApiClient.ts
CHANGED
|
@@ -35,13 +35,13 @@ export interface TranslateRequest {
|
|
|
35
35
|
documentId: string
|
|
36
36
|
translatePath: Path
|
|
37
37
|
languagePath?: string
|
|
38
|
-
styleguide
|
|
38
|
+
styleguide: () => Promise<string | undefined>
|
|
39
39
|
fieldLanguageMap?: FieldLanguageMap[]
|
|
40
40
|
conditionalMembers?: ConditionalMemberState[]
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const basePath = '/assist/tasks/instruction'
|
|
44
|
-
const API_VERSION_WITH_EXTENDED_TYPES = '2025-04-01'
|
|
44
|
+
export const API_VERSION_WITH_EXTENDED_TYPES = '2025-04-01'
|
|
45
45
|
|
|
46
46
|
export function canUseAssist(status: InstructStatus | undefined) {
|
|
47
47
|
return status?.enabled && status.initialized && status.validToken
|
|
@@ -73,8 +73,8 @@ export function useTranslate(apiClient: SanityClient) {
|
|
|
73
73
|
}: TranslateRequest) => {
|
|
74
74
|
setLoading(true)
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
.request({
|
|
76
|
+
async function run() {
|
|
77
|
+
return apiClient.request({
|
|
78
78
|
method: 'POST',
|
|
79
79
|
url: `/assist/tasks/translate/${apiClient.config().dataset}?projectId=${
|
|
80
80
|
apiClient.config().projectId
|
|
@@ -83,7 +83,7 @@ export function useTranslate(apiClient: SanityClient) {
|
|
|
83
83
|
documentId,
|
|
84
84
|
types,
|
|
85
85
|
languagePath,
|
|
86
|
-
userStyleguide: styleguide,
|
|
86
|
+
userStyleguide: await styleguide(),
|
|
87
87
|
fieldLanguageMap,
|
|
88
88
|
conditionalMembers,
|
|
89
89
|
translatePath:
|
|
@@ -91,6 +91,9 @@ export function useTranslate(apiClient: SanityClient) {
|
|
|
91
91
|
userId: user?.id,
|
|
92
92
|
},
|
|
93
93
|
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return run()
|
|
94
97
|
.catch((e) => {
|
|
95
98
|
toast.push({
|
|
96
99
|
status: 'error',
|