@sanity/assist 4.0.1 → 4.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/assist",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "description": "You create the instructions; Sanity AI Assist does the rest.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -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/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.length > 2000) {
50
- throw new Error(
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)) {
@@ -19,7 +19,8 @@ import {
19
19
 
20
20
  import {useAiAssistanceConfig} from '../assistLayout/AiAssistanceConfigContext'
21
21
  import type {ConditionalMemberState} from '../helpers/conditionalMembers'
22
- import {useApiClient, useTranslate} from '../useApiClient'
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({apiVersion: config?.apiVersion ?? '2022-11-27'})
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 type {
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({
@@ -148,7 +156,10 @@ export const translateActions: DocumentFieldAction = {
148
156
  getConditionalMembers(formStateRef.current)
149
157
  }
150
158
  openFieldTranslation({
151
- document: docRef.current,
159
+ document: {
160
+ ...docRef.current,
161
+ _id: documentId,
162
+ },
152
163
  documentSchema: documentSchemaType,
153
164
  translatePath: path,
154
165
  conditionalMembers: formStateRef.current
@@ -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?: string
196
+ styleguide?: TranslateStyleguide
181
197
  }
@@ -35,13 +35,13 @@ export interface TranslateRequest {
35
35
  documentId: string
36
36
  translatePath: Path
37
37
  languagePath?: string
38
- styleguide?: string
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
- return apiClient
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',