@sanity/assist 2.0.4-canary.0 → 2.0.4

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.
Files changed (2) hide show
  1. package/README.md +233 -214
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -34,7 +34,6 @@
34
34
  - [Develop \& test](#develop--test)
35
35
  - [Release new version](#release-new-version)
36
36
 
37
-
38
37
  ## About Sanity AI Assist
39
38
 
40
39
  Free your team to do more of what they’re great at (and less busywork) with the AI assistant that works with structured content. Attach reusable AI instructions to fields and documents to supercharge your editorial workflow.
@@ -68,14 +67,14 @@ This plugin requires `sanity` version `3.26` or greater.
68
67
  In `sanity.config.ts`, add `assist` to the `plugins` array:
69
68
 
70
69
  ```tsx
71
- import { assist } from '@sanity/assist'
70
+ import {assist} from '@sanity/assist'
72
71
 
73
72
  export default defineConfig({
74
73
  /* other config */
75
74
  plugins: [
76
75
  /* other plugins */
77
- assist()
78
- ]
76
+ assist(),
77
+ ],
79
78
  })
80
79
  ```
81
80
 
@@ -83,14 +82,14 @@ export default defineConfig({
83
82
 
84
83
  After installing and adding the plugin and having the AI Assist feature enabled for your project and its datasets, you need to create a token for the plugin to access the AI Assist API. This needs to be done by a member of the project with token creation permissions (typically someone with an admin or developer role).
85
84
 
86
- * Start the studio and open any document
87
- * Click *the sparkle icon** (✨) in the document header near the close document X-button
88
- * Then select **Manage instructions**
85
+ - Start the studio and open any document
86
+ - Click \*the sparkle icon\*\* (✨) in the document header near the close document X-button
87
+ - Then select **Manage instructions**
89
88
 
90
89
  <img width="210" alt="The AI Assist document menu showing 'Manage instructions' highlighted" src="https://github.com/sanity-io/sanity/assets/835514/58c177ca-4530-4f44-abe0-4adcd9e11c8b">
91
90
 
92
- * Selecting **Manage instructions** will open an inspector panel
93
- * Click the **Enable AI assistance** button to create a token and enable AI Assist for everyone with access to the project
91
+ - Selecting **Manage instructions** will open an inspector panel
92
+ - Click the **Enable AI assistance** button to create a token and enable AI Assist for everyone with access to the project
94
93
 
95
94
  <img width="339" alt="The 'Enable Sanity AI Assist' button" src="https://github.com/sanity-io/sanity/assets/835514/38b81861-6a7c-49a2-a7c5-f46816d0c0a8">
96
95
 
@@ -118,21 +117,20 @@ themselves can edit can be changed by the instruction instance.
118
117
 
119
118
  By default, most string, object, and array field types (including Portable Text!) have AI writing assistance enabled. Your assistant can write to all compatible fields that it detects.
120
119
 
121
-
122
120
  ### Disable AI Assist for a schema type
123
121
 
124
122
  ```tsx
125
123
  // this will disable AI assistance wherever it is used,
126
124
  // ie: as field, document, array types
127
125
  defineType({
128
- name: 'policy',
126
+ name: 'policy',
129
127
  type: 'document',
130
128
  options: {
131
- aiAssist: {exclude: true}
132
- },
129
+ aiAssist: {exclude: true},
130
+ },
133
131
  fields: [
134
132
  // ...
135
- ]
133
+ ],
136
134
  })
137
135
  ```
138
136
 
@@ -141,17 +139,17 @@ defineType({
141
139
  ```tsx
142
140
  // this disables AI assistance only for the specific field
143
141
  defineType({
144
- name: 'product',
142
+ name: 'product',
145
143
  type: 'object',
146
144
  fields: [
147
145
  defineField({
148
146
  name: 'sku',
149
147
  type: 'string',
150
148
  options: {
151
- aiAssist: {exclude: true}
152
- }
153
- })
154
- ]
149
+ aiAssist: {exclude: true},
150
+ },
151
+ }),
152
+ ],
155
153
  })
156
154
  ```
157
155
 
@@ -161,30 +159,31 @@ defineType({
161
159
  // this disables AI assistance for the specific array member
162
160
  // if all types in the `of` array are excluded, the array type is also considered excluded
163
161
  defineType({
164
- name: 'product',
162
+ name: 'product',
165
163
  type: 'array',
166
164
  of: [
167
165
  defineArrayMember({
168
166
  type: 'customProduct',
169
167
  options: {
170
- aiAssist: {exclude: true}
171
- }
172
- })
173
- ]
168
+ aiAssist: {exclude: true},
169
+ },
170
+ }),
171
+ ],
174
172
  })
175
173
  ```
176
174
 
177
175
  ### Unsupported types
178
176
 
179
177
  The following types are not supported, and behave as excluded types:
180
- * [Number](https://www.sanity.io/docs/number-type)
181
- * [Slug](https://www.sanity.io/docs/slug-type)
182
- * [Url](https://www.sanity.io/docs/url-type)
183
- * [Date](https://www.sanity.io/docs/date-type)
184
- * [Datetime](https://www.sanity.io/docs/datetime-type)
185
- * [Image](https://www.sanity.io/docs/image-type) (supported when image has custom fields)
186
- * [File](https://www.sanity.io/docs/file-type) (never supported, even when file has custom fields)
187
- * [Reference](https://www.sanity.io/docs/reference-type) (supported when configured with embeddingsIndex)
178
+
179
+ - [Number](https://www.sanity.io/docs/number-type)
180
+ - [Slug](https://www.sanity.io/docs/slug-type)
181
+ - [Url](https://www.sanity.io/docs/url-type)
182
+ - [Date](https://www.sanity.io/docs/date-type)
183
+ - [Datetime](https://www.sanity.io/docs/datetime-type)
184
+ - [Image](https://www.sanity.io/docs/image-type) (supported when image has custom fields)
185
+ - [File](https://www.sanity.io/docs/file-type) (never supported, even when file has custom fields)
186
+ - [Reference](https://www.sanity.io/docs/reference-type) (supported when configured with embeddingsIndex)
188
187
 
189
188
  Fields with these types will not be changed by the assistant, do not have AI Assist actions, and cannot be referenced in instructions.
190
189
 
@@ -198,23 +197,25 @@ These fields can be written to by an instruction, as long as the field is non-hi
198
197
 
199
198
  Fields with `hidden` or `readOnly` set to literal `true` will be skipped by AI Assist.
200
199
 
201
- *Note*: An instruction will not re-evaluate these states during a run.
200
+ _Note_: An instruction will not re-evaluate these states during a run.
202
201
  I.e., if an instruction makes a change during its execution that triggers another field to change its `hidden` or `readOnly` status,
203
202
  the running instruction will still consider these as if in their original state.
204
203
 
205
- If it is essential that AI Assist *never* writes to a conditional field,
204
+ If it is essential that AI Assist _never_ writes to a conditional field,
206
205
  it should be marked with `options.aiAssist.exclude: true`.
207
206
 
208
207
  ### Reference support
209
208
 
210
209
  #### Create an Embeddings-index
210
+
211
211
  To enable AI assist for references, first, your project must have an existing [embeddings-index](https://www.sanity.io/docs/embeddings-index-api-overview)
212
212
  that includes the document types it should be able to reference.
213
213
 
214
214
  You can manage your indexes directly in the studio using the [Embeddings Index Dashboard plugin](https://github.com/sanity-io/embeddings-index-ui#embeddings-index-api-dashboard-for-sanity-studio).
215
215
 
216
216
  #### Set schema options
217
- Set `options.aiAssist.embeddingsIndex` for reference fields/types you want to enable reference instructions for.
217
+
218
+ Set `options.aiAssist.embeddingsIndex` for reference fields/types you want to enable reference instructions for.
218
219
  Reference fields with this option set can have instructions attached and will be visited when running instructions for object fields and arrays.
219
220
 
220
221
  AI Assist will use the embeddings-index, further filtered by the types allowed by the reference, to look up contextually relevant references.
@@ -229,10 +230,10 @@ defineField({
229
230
  type: 'reference',
230
231
  name: 'articleReference',
231
232
  title: 'Article reference',
232
- to: [ { type: 'article'} ],
233
+ to: [{type: 'article'}],
233
234
  options: {
234
235
  aiAssist: {
235
- embeddingsIndex: 'article-index'
236
+ embeddingsIndex: 'article-index',
236
237
  },
237
238
  },
238
239
  })
@@ -251,59 +252,63 @@ If you have a very large schema (that is, many document and field types), it can
251
252
 
252
253
  We recommend excluding any and all types that aren't likely to benefit from automated workflows. A quick win is typically to exclude array types. It can be a good idea to exclude most non-block types from Portable Text arrays. This will ensure that AI Assist outputs mostly formatted text.
253
254
 
254
- It is also possible to exclude fields/types when creating an instruction. See [Field and type filters](#field-and-type-filters) for more.
255
+ It is also possible to exclude fields/types when creating an instruction. See [Field and type filters](#field-and-type-filters) for more.
255
256
 
256
257
  ## Included document types
257
258
 
258
- This plugin adds an `AI Context` document type.
259
+ This plugin adds an `AI Context` document type.
259
260
 
260
261
  If your Studio uses [Structure Builder](https://www.sanity.io/docs/structure-builder-introduction) to configure the studio structure,
261
262
  you might have to add this document type to your structure.
262
263
 
263
264
  The document type name can be imported from the plugin:
265
+
264
266
  ```ts
265
267
  import {contextDocumentTypeName} from '@sanity/assist'
266
268
 
267
- // put into structure in structure
269
+ // put into structure in structure
268
270
  S.documentTypeListItem(contextDocumentTypeName)
269
271
  ```
270
272
 
271
273
  ## Field and type filters
272
274
 
273
275
  When creating instructions for documents, object fields, array fields, or portable text fields, you can explicitly control what will be visited by AI Assist.
274
- By default, the assistant will include all compatible fields and types.
276
+ By default, the assistant will include all compatible fields and types.
275
277
 
276
278
  Opting out fields/types per instruction is done using the respective field/type filter checkboxes under the instruction.
277
- When using these filters, it is not necessary to tell AI Assist what to include in the instruction text itself.
279
+ When using these filters, it is not necessary to tell AI Assist what to include in the instruction text itself.
278
280
 
279
281
  Note that once the schema targeted by the instruction changes, the following behavior applies:
280
- * instructions that include all fields or types will automatically also include the new fields or types
281
- * instructions that have excluded one or more fields or types will NOT include the new fields or types
282
+
283
+ - instructions that include all fields or types will automatically also include the new fields or types
284
+ - instructions that have excluded one or more fields or types will NOT include the new fields or types
282
285
 
283
286
  ## Image description generation
287
+
284
288
  AI Assist can optionally generate descriptions for images. This has to be enabled on an image-type/field,
285
289
  by setting the `options.aiAssist.imageDescriptionField` on the image type, where `imageDescriptionField` is the field name of a
286
290
  custom string-field on the image object:
287
291
 
288
292
  ```tsx
289
293
  defineField({
290
- type: 'image',
291
- name: 'inlineImage',
292
- title: 'Image',
293
- fields: [
294
- defineField({
295
- type: 'string',
296
- name: 'altText',
297
- title: 'Alternative text',
298
- }),
299
- ],
300
- options: {
301
- aiAssist: {
302
- imageDescriptionField: 'altText',
303
- }
294
+ type: 'image',
295
+ name: 'inlineImage',
296
+ title: 'Image',
297
+ fields: [
298
+ defineField({
299
+ type: 'string',
300
+ name: 'altText',
301
+ title: 'Alternative text',
302
+ }),
303
+ ],
304
+ options: {
305
+ aiAssist: {
306
+ imageDescriptionField: 'altText',
304
307
  },
308
+ },
305
309
  })
306
310
  ```
311
+
307
312
  This will add a **Generate image description** action to the configured field.
308
313
  The **Generate image description** action will automatically run whenever the image changes.
309
314
 
@@ -311,15 +316,18 @@ The **Generate image description** action will automatically run whenever the im
311
316
  Fields within array items are not supported.
312
317
 
313
318
  ## Image generation
319
+
314
320
  <img width="600" alt="image" src="https://github.com/sanity-io/assist/assets/835514/c4de6791-f530-4cd1-b0c2-96ef988bc256">
315
321
 
316
322
  AI Assist can generate assets for images configured with a prompt field.
317
323
 
318
- An image is generated directly by using the **Generate image from prompt** instruction on the prompt field,
324
+ An image is generated directly by using the **Generate image from prompt** instruction on the prompt field,
319
325
  or indirectly whenever the image prompt field is written to by an AI Assist instruction.
320
326
 
321
327
  ### Configure
328
+
322
329
  To enable image generation for an image field, the image must:
330
+
323
331
  - set `options.aiAssist.imageInstructionField` to a child-path relative to the image
324
332
  - have a `string` or `text` field that corresponds to the `imageInstructionField` path
325
333
 
@@ -335,36 +343,38 @@ Use AI context documents to apply a reusable style guide to the prompt rewriting
335
343
  #### Example
336
344
 
337
345
  Given the following document schema
346
+
338
347
  ```ts
339
348
  defineType({
340
349
  type: 'document',
341
- name: 'article',
342
- fields: [
343
- defineField({
344
- type: 'image',
345
- name: 'articleImage',
346
- fields: [
347
- defineField({
348
- type: 'text',
349
- name: 'imagePrompt',
350
- title: 'Image prompt',
351
- rows: 2,
352
- }),
353
- ],
354
- options: {
355
- imagePromptField: 'imagePromptField',
356
- },
357
- })
358
- ]
350
+ name: 'article',
351
+ fields: [
352
+ defineField({
353
+ type: 'image',
354
+ name: 'articleImage',
355
+ fields: [
356
+ defineField({
357
+ type: 'text',
358
+ name: 'imagePrompt',
359
+ title: 'Image prompt',
360
+ rows: 2,
361
+ }),
362
+ ],
363
+ options: {
364
+ imagePromptField: 'imagePromptField',
365
+ },
366
+ }),
367
+ ],
359
368
  })
360
369
  ```
361
370
 
362
- To directly generate an image based on the value in the prompt field,
371
+ To directly generate an image based on the value in the prompt field,
363
372
  run the "Generate image from prompt" instruction that is automatically added.
364
373
 
365
374
  For better image results or to ensure a consistent style, rewrite the prompt before generating the image:
366
375
 
367
376
  ### Example prompt expansion instruction
377
+
368
378
  <img width="267" alt="image" src="https://github.com/sanity-io/assist/assets/835514/dabc6910-80d3-4a69-940f-49ac5cae9ade">
369
379
 
370
380
  For better image results, use an instruction that expands the prompt to be more detailed.
@@ -388,7 +398,9 @@ The prompt to rewrite is:
388
398
  ```
389
399
 
390
400
  The rules can be extracted into an AI Context document and reused in other instructions as needed. This approach can also be used to inform a reusable styleguide for image generation.
401
+
391
402
  ## Full document translation
403
+
392
404
  <img width="250" alt="Translate document action" src="https://github.com/sanity-io/assist/assets/835514/932968ee-1a8c-4389-8822-338188f88b40">
393
405
 
394
406
  AI assist offers full document translations, which is ideal for pairing with [@sanity/document-internationalization](https://github.com/sanity-io/document-internationalization).
@@ -420,27 +432,28 @@ If the studio is using [@sanity/document-internationalization](https://github.co
420
432
  ```ts
421
433
  // This will add a "Translate document" instruction to all documents with a language field
422
434
  assist({
423
- translate: {
424
- document: {
425
- languageField: 'language'
426
- }
427
- }
435
+ translate: {
436
+ document: {
437
+ languageField: 'language',
438
+ },
439
+ },
428
440
  })
429
441
  ```
430
442
 
431
443
  ```ts
432
444
  // This will add a "Translate document" instruction only to the 'article' document type
433
445
  assist({
434
- translate: {
435
- document: {
436
- languageField: 'language',
437
- documentTypes: ['article']
438
- }
439
- }
446
+ translate: {
447
+ document: {
448
+ languageField: 'language',
449
+ documentTypes: ['article'],
450
+ },
451
+ },
440
452
  })
441
453
  ```
442
454
 
443
455
  **All configuration params**
456
+
444
457
  ```ts
445
458
  assist({
446
459
  translate: {
@@ -472,6 +485,7 @@ assist({
472
485
  ```
473
486
 
474
487
  ## Field level translations
488
+
475
489
  <img width="250" alt="Translate fields action" src="https://github.com/sanity-io/assist/assets/835514/99819cd4-578e-43b2-8c70-8e39afff5f09">
476
490
 
477
491
  <img width="250" alt="Translate fields dialog" src="https://github.com/sanity-io/assist/assets/835514/fe3d289c-49b6-46dd-ae2f-cd509a01534a">
@@ -489,20 +503,21 @@ AI Assist supports complex values, so language fields that hold nested objects,
489
503
  When initiating translations, editors select a language to translate from and which languages to translate to. This means that AI Assist supports partial translations in cases where editors are responsible for only some languages in the document.
490
504
 
491
505
  ### Configure field translations
506
+
492
507
  To enable field-level translations, set `translate.field.documentTypes` to an array with which document types should get field translations, and `translate.field.languages`
493
508
 
494
509
  ```ts
495
510
  assist({
496
- translate: {
497
- field: {
498
- documentTypes: ['article'],
499
- languages: [
500
- {id: 'en', title: 'English'},
501
- {id: 'de', title: 'German'}
502
- ]
503
- },
504
- },
505
- })
511
+ translate: {
512
+ field: {
513
+ documentTypes: ['article'],
514
+ languages: [
515
+ {id: 'en', title: 'English'},
516
+ {id: 'de', title: 'German'},
517
+ ],
518
+ },
519
+ },
520
+ })
506
521
  ```
507
522
 
508
523
  These documents will get a **Translate fields** instruction added to the document AI Assist dropdown.
@@ -511,76 +526,76 @@ Out of the box, this is sufficient config for document types using the `internat
511
526
 
512
527
  It will also work without further config for object types named `locale*`, (e.g. `localeTitle`, `localeDescription`) with one field per language:
513
528
 
514
- *Example locale object supported by default*
529
+ _Example locale object supported by default_
515
530
 
516
531
  ```ts
517
532
  // Object type with name starting with 'locale', and one field per language language
518
533
  defineType({
519
- type: 'object',
534
+ type: 'object',
520
535
  name: 'localeString',
521
536
  fields: [
522
- defineField({
537
+ defineField({
523
538
  // these do not have to be string, could be any type
524
- type: 'string',
539
+ type: 'string',
525
540
  name: 'en',
526
- title: 'English'
527
- }),
528
- defineField({
529
- type: 'string',
541
+ title: 'English',
542
+ }),
543
+ defineField({
544
+ type: 'string',
530
545
  name: 'de',
531
- title: 'German'
532
- })
533
- ]
546
+ title: 'German',
547
+ }),
548
+ ],
534
549
  })
535
550
  ```
536
551
 
537
552
  **If your schema is not using either of these structures**, refer to the section on [Custom language fields](#custom-language-fields).
538
553
 
539
554
  ### Loading field languages
555
+
540
556
  Languages must be an array of objects with an id and title.
541
557
 
542
558
  ```ts
543
559
  assist({
544
- translate: {
545
- field: {
546
- languages: [
547
- {id: 'en', title: 'English'},
548
- {id: 'de', title: 'German'}
549
- ]
550
- },
551
- },
552
- })
560
+ translate: {
561
+ field: {
562
+ languages: [
563
+ {id: 'en', title: 'English'},
564
+ {id: 'de', title: 'German'},
565
+ ],
566
+ },
567
+ },
568
+ })
553
569
  ```
554
570
 
555
571
  Or an asynchronous function that returns an array of objects with an id and title.
556
572
 
557
573
  ```ts
558
574
  assist({
559
- translate: {
560
- field: {
561
- languages: async () => {
562
- const response = await fetch('https://example.com/languages')
563
- return response.json()
564
- }
565
- },
575
+ translate: {
576
+ field: {
577
+ languages: async () => {
578
+ const response = await fetch('https://example.com/languages')
579
+ return response.json()
566
580
  },
567
- })
581
+ },
582
+ },
583
+ })
568
584
  ```
569
585
 
570
586
  The async function contains a configured Sanity client in the first parameter, allowing you to store language options as documents. Your query should return an array of objects with an id and title.
571
587
 
572
-
573
588
  ```ts
574
589
  assist({
575
- translate: {
576
- field: {
577
- languages: async () => {
578
- const response = await client.fetch(`*[_type == "language"]{ id, title }`)
579
- return response
580
- }
581
- },
590
+ translate: {
591
+ field: {
592
+ languages: async () => {
593
+ const response = await client.fetch(`*[_type == "language"]{ id, title }`)
594
+ return response
582
595
  },
583
- })
596
+ },
597
+ },
598
+ })
584
599
  ```
585
600
 
586
601
  Additionally, you can "pick" fields from a document, to pass into the query. For example, if you have a concept of "Markets" where only certain language fields are required in certain markets.
@@ -589,24 +604,25 @@ In this example, each language document has an array of strings called markets t
589
604
 
590
605
  ```ts
591
606
  assist({
592
- translate: {
593
- field: {
594
- selectLanguageParams: {
595
- market: 'market'
596
- },
597
- languages: async (client, {market = ``}) => {
598
- const response = await client.fetch(
599
- `*[_type == "language" && $market in markets]{ id, title }`,
600
- {market}
601
- )
602
- return response
603
- },
604
- },
607
+ translate: {
608
+ field: {
609
+ selectLanguageParams: {
610
+ market: 'market',
605
611
  },
606
- })
612
+ languages: async (client, {market = ``}) => {
613
+ const response = await client.fetch(
614
+ `*[_type == "language" && $market in markets]{ id, title }`,
615
+ {market}
616
+ )
617
+ return response
618
+ },
619
+ },
620
+ },
621
+ })
607
622
  ```
608
623
 
609
624
  ### Custom language fields
625
+
610
626
  By providing a function to `translate.field.translationOutputs`, you have complete control over which fields belong to which language.
611
627
 
612
628
  `translationOutputs` is used when an editor uses the **Translate fields** instruction.
@@ -615,10 +631,10 @@ It determines the relationships between document paths: Given a document path an
615
631
 
616
632
  `translationOutputs` is invoked once per path in the document (limited to a depth of 6), with the following arguments:
617
633
 
618
- * `documentMember` - the field or array item for a given path; contains the path and its `schemaType`
619
- * `enclosingType` - the schema type of the parent holding the member
620
- * `translateFromLanguageId` - the `languageId` for the language the users want to translate from
621
- * `translateToLanguageIds` - all `languageId`s the user can translate to
634
+ - `documentMember` - the field or array item for a given path; contains the path and its `schemaType`
635
+ - `enclosingType` - the schema type of the parent holding the member
636
+ - `translateFromLanguageId` - the `languageId` for the language the users want to translate from
637
+ - `translateToLanguageIds` - all `languageId`s the user can translate to
622
638
 
623
639
  The function should return a `TranslationOutput[]` array that contains all the paths where translations from `documentMember` (in the language received in `translateFromLanguageId`) should be output.
624
640
 
@@ -635,7 +651,7 @@ Given the following document:
635
651
  ```ts
636
652
  {
637
653
  titles: {
638
- _type: 'languageObject',
654
+ _type: 'languageObject',
639
655
  en: {
640
656
  _type: 'titleObject',
641
657
  title: 'Some title',
@@ -653,8 +669,8 @@ invoked multiple times.
653
669
 
654
670
  The following parameters will be the same every invocation:
655
671
 
656
- * `translateFromLanguageId` will be `'en'`
657
- * `translateToLanguageIds` will be `['de']`
672
+ - `translateFromLanguageId` will be `'en'`
673
+ - `translateToLanguageIds` will be `['de']`
658
674
 
659
675
  `documentMember` and `enclosingType` will change between each invocation, and take the following values:
660
676
 
@@ -669,22 +685,27 @@ To indicate that you want everything under `title.en` to be translated into `tit
669
685
  The following function enables this:
670
686
 
671
687
  ```ts
672
- function translationOutputs(member, enclosingType, translateFromLanguageId, translateToLanguageIds) {
673
- const parentIsLanguageWrapper = enclosingType.jsonType === 'object' && enclosingType.name.startsWith('language')
674
-
675
- if (parentIsLanguageWrapper && translateFromLanguageId === member.name) {
676
-
688
+ function translationOutputs(
689
+ member,
690
+ enclosingType,
691
+ translateFromLanguageId,
692
+ translateToLanguageIds
693
+ ) {
694
+ const parentIsLanguageWrapper =
695
+ enclosingType.jsonType === 'object' && enclosingType.name.startsWith('language')
696
+
697
+ if (parentIsLanguageWrapper && translateFromLanguageId === member.name) {
677
698
  // [id: 'de', ]
678
- return translateToLanguageIds.map((translateToId) => ({
679
- id: translateToId,
680
- // in this example, member.path is 'titles.en'
681
- // so this changes titles.en -> titles.de
682
- outputPath: [...member.path.slice(0, -1), translateToId],
683
- }))
684
- }
685
-
686
- // ignore other members
687
- return undefined
699
+ return translateToLanguageIds.map((translateToId) => ({
700
+ id: translateToId,
701
+ // in this example, member.path is 'titles.en'
702
+ // so this changes titles.en -> titles.de
703
+ outputPath: [...member.path.slice(0, -1), translateToId],
704
+ }))
705
+ }
706
+
707
+ // ignore other members
708
+ return undefined
688
709
  }
689
710
  ```
690
711
 
@@ -692,35 +713,36 @@ function translationOutputs(member, enclosingType, translateFromLanguageId, tran
692
713
 
693
714
  ```ts
694
715
  assist({
695
- translate: {
696
- field: {
697
- documentTypes: ['article'],
698
- selectLanguageParams: {market: 'market'},
699
- apiVersion: '2023-01-01',
700
- languages: (client, {market}) => {
701
- return client.fetch(
702
- `*[_type == "language" && $market in markets]{ id, title }`,
703
- {market}
704
- )
705
- },
706
- translationOutputs: (member, enclosingType, fromLanguageId, toLanguageIds) => {
707
- // When the document member is named the same as fromLangagueId
708
- // and it is a field in a object with a name starting with "language"
709
- // then we return the paths to all other sibling language fields (and their langauge id)
710
- // It is ok that the member is an object, then all child fields will be translated
711
- if (translateFromLanguageId === member.name && enclosingType.jsonType === 'object' && enclosingType.name.startsWith('locale')) {
712
- return translateToLanguageIds.map((translateToId) => ({
713
- id: translateToId,
714
- //changes path.to.en -> path.to.de (for instance)
715
- outputPath: [...member.path.slice(0, -1), translateToId],
716
- }))
717
- }
718
- // all other member paths are skipped
719
- return undefined
720
- }
721
- },
716
+ translate: {
717
+ field: {
718
+ documentTypes: ['article'],
719
+ selectLanguageParams: {market: 'market'},
720
+ apiVersion: '2023-01-01',
721
+ languages: (client, {market}) => {
722
+ return client.fetch(`*[_type == "language" && $market in markets]{ id, title }`, {market})
723
+ },
724
+ translationOutputs: (member, enclosingType, fromLanguageId, toLanguageIds) => {
725
+ // When the document member is named the same as fromLangagueId
726
+ // and it is a field in a object with a name starting with "language"
727
+ // then we return the paths to all other sibling language fields (and their langauge id)
728
+ // It is ok that the member is an object, then all child fields will be translated
729
+ if (
730
+ translateFromLanguageId === member.name &&
731
+ enclosingType.jsonType === 'object' &&
732
+ enclosingType.name.startsWith('locale')
733
+ ) {
734
+ return translateToLanguageIds.map((translateToId) => ({
735
+ id: translateToId,
736
+ //changes path.to.en -> path.to.de (for instance)
737
+ outputPath: [...member.path.slice(0, -1), translateToId],
738
+ }))
739
+ }
740
+ // all other member paths are skipped
741
+ return undefined
722
742
  },
723
- })
743
+ },
744
+ },
745
+ })
724
746
  ```
725
747
 
726
748
  ## Adding translation actions to fields
@@ -740,31 +762,29 @@ For document types configured for full document translations, a **Translate** ac
740
762
 
741
763
  For document types configured for field translations, a **Translate fields...** action will be added. Running it will open a dialog with language selectors.
742
764
 
743
-
744
765
  #### Example
745
766
 
746
767
  ```ts
747
768
  defineField({
748
- name: 'subtitle',
749
- type: 'internationalizedArrayString',
750
- title: 'Subtitle',
751
- options: {
752
- aiAssist: {
753
- translateAction: true
754
- }
769
+ name: 'subtitle',
770
+ type: 'internationalizedArrayString',
771
+ title: 'Subtitle',
772
+ options: {
773
+ aiAssist: {
774
+ translateAction: true,
755
775
  },
776
+ },
756
777
  })
757
778
  ```
758
779
 
759
780
  ## Caveats
760
781
 
761
- Large Language Models (LLMs) are a new technology. Constraints and limitations are still being explored,
782
+ Large Language Models (LLMs) are a new technology. Constraints and limitations are still being explored,
762
783
  but some common caveats to the field that you may run into using AI Assist are:
763
784
 
764
- * Limits to instruction length: Long instructions on deep content structures may exhaust model context
765
- * Timeouts: To be able to write structured content, we're using the largest language models - long-running results may time out or intermittently fail
766
- * Limited capacity: The underlying LLM APIs used by AI Assist are resource-constrained
767
-
785
+ - Limits to instruction length: Long instructions on deep content structures may exhaust model context
786
+ - Timeouts: To be able to write structured content, we're using the largest language models - long-running results may time out or intermittently fail
787
+ - Limited capacity: The underlying LLM APIs used by AI Assist are resource-constrained
768
788
 
769
789
  ## Third party sub-processors
770
790
 
@@ -782,7 +802,6 @@ with default configuration for build & watch scripts.
782
802
  See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
783
803
  on how to run this plugin with hotreload in the studio.
784
804
 
785
-
786
805
  ### Release new version
787
806
 
788
807
  Run ["CI & Release" workflow](https://github.com/sanity-io/sanity/actions/workflows/main.yml).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/assist",
3
- "version": "2.0.4-canary.0",
3
+ "version": "2.0.4",
4
4
  "description": "You create the instructions; Sanity AI Assist does the rest.",
5
5
  "keywords": [
6
6
  "sanity",