@sanity/assist 3.0.5 → 3.0.7

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/dist/index.js CHANGED
@@ -28,7 +28,7 @@ function isWelcomeEvent(event) {
28
28
  return event.type === "welcome";
29
29
  }
30
30
  const listenQuery = (client, query, params = {}, options2 = {}) => {
31
- const fetchQuery = typeof query == "string" ? query : query.fetch, listenerQuery = typeof query == "string" ? query : query.listen, fetchOnce$ = fetch(client, fetchQuery, params, options2), events$ = listen(client, listenerQuery, params, options2).pipe(
31
+ const fetchQuery = query, listenerQuery = query, fetchOnce$ = fetch(client, fetchQuery, params, options2), events$ = listen(client, listenerQuery, params, options2).pipe(
32
32
  operators.mergeMap((ev, i) => i === 0 && !isWelcomeEvent(ev) ? rxjs.throwError(
33
33
  new Error(
34
34
  ev.type === "reconnect" ? "Could not establish EventSource connection" : `Received unexpected type of first event "${ev.type}"`
@@ -46,12 +46,12 @@ const listenQuery = (client, query, params = {}, options2 = {}) => {
46
46
  }, DEFAULT_PARAMS = {}, DEFAULT_OPTIONS = { apiVersion: "v2022-05-09" };
47
47
  function useListeningQuery(query, params = DEFAULT_PARAMS, options2 = DEFAULT_OPTIONS) {
48
48
  const [loading, setLoading] = react.useState(!0), [error, setError] = react.useState(!1), [data, setData] = react.useState(null), subscription = react.useRef(null), client = sanity.useClient({ apiVersion: "v2022-05-09" });
49
- return react.useEffect(() => (query && (subscription.current = listenQuery(client, query, params, options2).pipe(
49
+ return react.useEffect(() => (subscription.current = listenQuery(client, query, params, options2).pipe(
50
50
  operators.distinctUntilChanged(isEqual__default.default),
51
51
  operators.catchError((err) => (console.error(err), setError(err), setLoading(!1), setData(null), err))
52
52
  ).subscribe((documents) => {
53
53
  setData((current) => isEqual__default.default(current, documents) ? current : documents), setLoading(!1), setError(!1);
54
- })), () => subscription.current ? subscription.current.unsubscribe() : void 0), [query, params, options2, client]), { loading, error, data };
54
+ }), () => subscription.current ? subscription.current.unsubscribe() : void 0), [query, params, options2, client]), { loading, error, data };
55
55
  }
56
56
  const assistDocumentIdPrefix = "sanity.assist.schemaType.", assistDocumentStatusIdPrefix = "sanity.assist.status.", assistSchemaIdPrefix = "sanity.assist.schema.", assistDocumentTypeName = "sanity.assist.schemaType.annotations", assistFieldTypeName = "sanity.assist.schemaType.field", instructionTypeName = "sanity.assist.instruction", promptTypeName = "sanity.assist.instruction.prompt", userInputTypeName = "sanity.assist.instruction.userInput", instructionContextTypeName = "sanity.assist.instruction.context", fieldReferenceTypeName = "sanity.assist.instruction.fieldRef", contextDocumentTypeName = "assist.instruction.context", assistTasksStatusTypeName = "sanity.assist.task.status", instructionTaskTypeName = "sanity.assist.instructionTask", fieldPresenceTypeName = "sanity.assist.instructionTask.presence", assistSerializedTypeName = "sanity.assist.serialized.type", assistSerializedFieldTypeName = "sanity.assist.serialized.field", outputFieldTypeName = "sanity.assist.output.field", outputTypeTypeName = "sanity.assist.output.type", fieldPathParam = "pathKey", instructionParam = "instruction", documentRootKey = "<document>";
57
57
  function isPortableTextArray(type) {
@@ -475,100 +475,81 @@ function prepareRebaseEvent(event) {
475
475
  )
476
476
  };
477
477
  }
478
- const SelectedFieldContext = react.createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, maxDepth = 6;
479
- function getTypeIcon(schemaType) {
480
- let t = schemaType;
481
- for (; t; ) {
482
- if (t.icon)
483
- return t.icon;
484
- t = t.type;
485
- }
486
- return isType(schemaType, "slug") ? icons.LinkIcon : isType(schemaType, "image") ? icons.ImageIcon : schemaType.jsonType === "array" && isPortableTextArray(schemaType) ? icons.BlockContentIcon : schemaType.jsonType === "array" ? icons.OlistIcon : schemaType.jsonType === "object" ? icons.BlockquoteIcon : schemaType.jsonType === "string" ? icons.StringIcon : icons.DocumentIcon;
487
- }
488
- function getFieldRefsWithDocument(schemaType) {
489
- var _a;
490
- const fields = getFieldRefs(schemaType);
491
- return [
492
- {
493
- key: documentRootKey,
494
- icon: (_a = schemaType.icon) != null ? _a : icons.DocumentIcon,
495
- title: "The entire document",
496
- path: [],
497
- schemaType
498
- },
499
- ...fields
500
- ];
478
+ const AssistTypeContext = react.createContext({}), illegalIdChars = /[^a-zA-Z0-9._-]/g;
479
+ function publicId(id) {
480
+ return id.replace("drafts.", "");
501
481
  }
502
- function getFieldRefs(schemaType, parent, depth = 0) {
503
- return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
504
- var _a;
505
- const path = parent ? [...parent.path, field.name] : [field.name], title = (_a = field.type.title) != null ? _a : field.name, fieldRef = {
506
- key: patchableKey(sanity.pathToString(path)),
507
- path,
508
- title: parent ? [parent.title, title].join(" / ") : title,
509
- schemaType: field.type,
510
- icon: getTypeIcon(field.type)
511
- }, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
512
- return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
513
- });
482
+ function assistDocumentId(documentType) {
483
+ return `${assistDocumentIdPrefix}${documentType}`.replace(illegalIdChars, "_");
514
484
  }
515
- function getSyntheticFields(schemaType, parent, depth = 0) {
516
- return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
517
- var _a;
518
- const segment = { _key: itemType.name }, title = (_a = itemType.title) != null ? _a : itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
519
- key: patchableKey(sanity.pathToString(path)),
520
- path,
521
- title: parent ? [parent.title, title].join(" / ") : title,
522
- schemaType: itemType,
523
- icon: getTypeIcon(itemType),
524
- synthetic: !0
525
- }, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
526
- return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
527
- });
485
+ function assistTasksStatusId(documentId) {
486
+ return `${assistDocumentStatusIdPrefix}${publicId(documentId)}`;
528
487
  }
529
- function getTypePath(doc, pathString) {
530
- if (!pathString)
531
- return;
532
- const path = sanity.stringToPath(pathString), currentPath = [];
533
- let valid = !0;
534
- const syntheticPath = path.map((segment) => {
535
- if (currentPath.push(segment), sanity.isKeySegment(segment)) {
536
- const match = mutator.extractWithPath(sanity.pathToString(currentPath), doc)[0], value = match == null ? void 0 : match.value;
537
- if (match && value && typeof value == "object" && "_type" in value)
538
- return { _key: value._type };
539
- valid = !1;
540
- }
541
- return segment;
542
- });
543
- return valid ? patchableKey(sanity.pathToString(syntheticPath)) : void 0;
488
+ function useDocumentState(id, docType) {
489
+ const state = sanity.useEditState(id, docType);
490
+ return state.draft || state.published;
544
491
  }
545
- function patchableKey(pathKey) {
546
- return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
492
+ function useStudioAssistDocument({
493
+ documentId,
494
+ schemaType,
495
+ initDoc
496
+ }) {
497
+ const documentTypeName = schemaType.name, currentUser = sanity.useCurrentUser(), assistDocument = useDocumentState(
498
+ assistDocumentId(documentTypeName),
499
+ assistDocumentTypeName
500
+ ), assistTasksStatus = useDocumentState(
501
+ assistTasksStatusId(documentId != null ? documentId : ""),
502
+ assistTasksStatusTypeName
503
+ ), client = sanity.useClient({ apiVersion: "2023-01-01" });
504
+ return react.useEffect(() => {
505
+ !assistDocument && initDoc && client.createIfNotExists({
506
+ _id: assistDocumentId(documentTypeName),
507
+ _type: assistDocumentTypeName
508
+ }).catch(() => {
509
+ });
510
+ }, [client, assistDocument, documentTypeName, initDoc]), react.useMemo(() => {
511
+ var _a, _b;
512
+ if (!assistDocument)
513
+ return;
514
+ const tasks = (_a = assistTasksStatus == null ? void 0 : assistTasksStatus.tasks) != null ? _a : [], fields = ((_b = assistDocument == null ? void 0 : assistDocument.fields) != null ? _b : []).map((assistField) => {
515
+ var _a2;
516
+ return {
517
+ ...assistField,
518
+ tasks: tasks.filter((task) => task.path === assistField.path),
519
+ instructions: (_a2 = assistField.instructions) == null ? void 0 : _a2.filter((p) => !p.userId || p.userId === (currentUser == null ? void 0 : currentUser.id)).map((instruction2) => asStudioInstruction(instruction2, tasks))
520
+ };
521
+ });
522
+ return sanity.typed({
523
+ ...assistDocument,
524
+ tasks: tasks == null ? void 0 : tasks.map((task) => {
525
+ var _a2, _b2;
526
+ const instruction2 = (_b2 = (_a2 = fields.find((f) => f.path === task.path)) == null ? void 0 : _a2.instructions) == null ? void 0 : _b2.find((i) => i._key === task.instructionKey);
527
+ return {
528
+ ...task,
529
+ instruction: instruction2
530
+ };
531
+ }),
532
+ fields
533
+ });
534
+ }, [assistDocument, assistTasksStatus, currentUser]);
547
535
  }
548
- function useTypePath(doc, pathString) {
549
- return react.useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
536
+ function asStudioInstruction(instruction2, run) {
537
+ return {
538
+ ...instruction2,
539
+ tasks: run.filter((task) => task.instructionKey === instruction2._key).filter(
540
+ (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
541
+ )
542
+ };
550
543
  }
551
- function useSelectedField(documentSchemaType, path) {
552
- const selectableFields = react.useMemo(
553
- () => documentSchemaType && sanity.isObjectSchemaType(documentSchemaType) ? getFieldRefsWithDocument(documentSchemaType) : [],
554
- [documentSchemaType]
555
- );
556
- return react.useMemo(() => path ? selectableFields == null ? void 0 : selectableFields.find((f) => f.key === path) : void 0, [selectableFields, path]);
544
+ function usePathKey(path) {
545
+ return react.useMemo(() => getPathKey(path), [path]);
557
546
  }
558
- function getFieldTitle(field) {
559
- var _a, _b, _c;
560
- const schemaType = field == null ? void 0 : field.schemaType;
561
- return (_c = (_b = (_a = field == null ? void 0 : field.title) != null ? _a : schemaType == null ? void 0 : schemaType.title) != null ? _b : schemaType == null ? void 0 : schemaType.name) != null ? _c : "Untitled";
547
+ function getPathKey(path) {
548
+ return path.length ? Array.isArray(path) ? sanity.pathToString(path) : path : documentRootKey;
562
549
  }
563
- function useAiPaneRouter() {
564
- const paneRouter = structure.usePaneRouter();
565
- return react.useMemo(
566
- () => {
567
- var _a;
568
- return { ...paneRouter, params: (_a = paneRouter.params) != null ? _a : {} };
569
- },
570
- [paneRouter]
571
- );
550
+ function getInstructionTitle(instruction2) {
551
+ var _a;
552
+ return (_a = instruction2 == null ? void 0 : instruction2.title) != null ? _a : "Untitled";
572
553
  }
573
554
  const basePath = "/assist/tasks/instruction";
574
555
  function canUseAssist(status) {
@@ -772,252 +753,12 @@ function AiAssistanceConfigProvider(props) {
772
753
  }, [initInstruct, getInstructStatus, setStatus]), { config, children } = props, context = react.useMemo(() => ({
773
754
  config,
774
755
  status,
775
- statusLoading,
776
- init,
777
- initLoading,
778
- error
779
- }), [config, status, init, statusLoading, initLoading, error]);
780
- return /* @__PURE__ */ jsxRuntime.jsx(AiAssistanceConfigContext.Provider, { value: context, children });
781
- }
782
- const aiDocPrefixPattern = new RegExp(`^${assistDocumentIdPrefix}`);
783
- function publicId(id) {
784
- return id.replace("drafts.", "");
785
- }
786
- function assistDocumentId(documentType) {
787
- return `${assistDocumentIdPrefix}${documentType}`;
788
- }
789
- function documentTypeFromAiDocumentId(id) {
790
- return id.replace(aiDocPrefixPattern, "");
791
- }
792
- function assistTasksStatusId(documentId) {
793
- return `${assistDocumentStatusIdPrefix}${publicId(documentId)}`;
794
- }
795
- const aiInspectorId = "ai-assistance";
796
- function BackToInstructionListLink() {
797
- const { openInspector } = structure.useDocumentPane(), goBack = react.useCallback(
798
- () => openInspector(aiInspectorId, { [instructionParam]: void 0 }),
799
- [openInspector]
800
- );
801
- return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
802
- ui.Button,
803
- {
804
- as: "a",
805
- fontSize: 1,
806
- icon: icons.ArrowLeftIcon,
807
- mode: "bleed",
808
- padding: 1,
809
- space: 2,
810
- onClick: goBack,
811
- text: " Instructions",
812
- textAlign: "left"
813
- }
814
- ) });
815
- }
816
- const EMPTY_FIELDS = [], TypePathContext = react.createContext(void 0);
817
- function AssistDocumentForm(props) {
818
- return props.readOnly ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { border: !0, tone: "caution", padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: " You do not have sufficient permissions to manage instructions." }) }) : /* @__PURE__ */ jsxRuntime.jsx(AssistDocumentFormEditable, { ...props });
819
- }
820
- function AssistDocumentFormEditable(props) {
821
- const { onChange } = props, value = props.value, id = value == null ? void 0 : value._id, fields = value == null ? void 0 : value.fields, targetDocumentType = react.useMemo(() => {
822
- if (id)
823
- return documentTypeFromAiDocumentId(id);
824
- }, [id]), { params, setParams } = useAiPaneRouter(), pathKey = params[fieldPathParam], typePath = react.useContext(TypePathContext), instruction2 = params[instructionParam], activeKey = react.useMemo(() => {
825
- var _a;
826
- if (typePath)
827
- return (_a = (fields != null ? fields : EMPTY_FIELDS).find((f) => f.path === typePath)) == null ? void 0 : _a._key;
828
- }, [fields, typePath]), activePath = react.useMemo(() => {
829
- if (!activeKey)
830
- return;
831
- const base = ["fields", { _key: activeKey }];
832
- return instruction2 ? [...base, "instructions", { _key: instruction2 }] : base;
833
- }, [activeKey, instruction2]), schema = sanity.useSchema(), documentSchema = react.useMemo(() => {
834
- if (targetDocumentType)
835
- return schema.get(targetDocumentType);
836
- }, [schema, targetDocumentType]), fieldSchema = useSelectedSchema(pathKey, documentSchema), context = react.useMemo(
837
- () => ({
838
- documentSchema,
839
- fieldSchema: fieldSchema != null ? fieldSchema : documentSchema
840
- }),
841
- [fieldSchema, documentSchema]
842
- ), title = value == null ? void 0 : value.title;
843
- react.useEffect(() => {
844
- var _a;
845
- !title && documentSchema && !(id != null && id.startsWith("drafts.")) && onChange(sanity.set((_a = documentSchema.title) != null ? _a : documentSchema.name, ["title"]));
846
- }, [title, documentSchema, onChange, id]);
847
- const { onPathOpen, ...formCallbacks } = sanity.useFormCallbacks(), newCallbacks = react.useMemo(
848
- () => ({
849
- ...formCallbacks,
850
- onPathOpen: (path) => {
851
- var _a;
852
- !instruction2 && path.length === 4 && path[2] === "instructions" ? (setParams(
853
- sanity.typed({
854
- ...params,
855
- [instructionParam]: (_a = path[3]) == null ? void 0 : _a._key
856
- })
857
- ), onPathOpen([])) : setTimeout(() => onPathOpen(path), 0);
858
- }
859
- }),
860
- [formCallbacks, onPathOpen, params, setParams, instruction2]
861
- );
862
- return react.useEffect(() => {
863
- activePath && !instruction2 && onPathOpen([]);
864
- }, [activePath, instruction2, onPathOpen]), /* @__PURE__ */ jsxRuntime.jsx(SelectedFieldContextProvider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 5, children: [
865
- /* @__PURE__ */ jsxRuntime.jsx(
866
- FieldsInitializer,
867
- {
868
- pathKey: typePath,
869
- activePath,
870
- fields,
871
- documentSchema,
872
- onChange
873
- },
874
- typePath
875
- ),
876
- instruction2 && /* @__PURE__ */ jsxRuntime.jsx(BackToInstructionListLink, {}),
877
- activePath && /* @__PURE__ */ jsxRuntime.jsx(sanity.FormCallbacksProvider, { ...newCallbacks, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { lineHeight: "1.25em" }, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.FormInput, { ...props, absolutePath: activePath }) }) }),
878
- !activePath && props.renderDefault(props)
879
- ] }) });
880
- }
881
- function useSelectedSchema(fieldPath, documentSchema) {
882
- return react.useMemo(() => {
883
- if (!fieldPath)
884
- return;
885
- if (fieldPath === documentRootKey)
886
- return documentSchema;
887
- const path = sanity.stringToPath(fieldPath);
888
- let currentSchema = documentSchema;
889
- for (let i = 0; i < path.length; i++) {
890
- const segment = path[i], field = currentSchema == null ? void 0 : currentSchema.fields.find((f) => f.name === segment);
891
- if (!field)
892
- return;
893
- if (i === path.length - 1)
894
- return field.type;
895
- if (field.type.jsonType !== "object")
896
- return;
897
- currentSchema = field.type;
898
- }
899
- return currentSchema;
900
- }, [documentSchema, fieldPath]);
901
- }
902
- function FieldsInitializer({
903
- pathKey,
904
- activePath,
905
- fields,
906
- documentSchema,
907
- onChange
908
- }) {
909
- const {
910
- config: { __presets: presets }
911
- } = useAiAssistanceConfig(), existingField = fields == null ? void 0 : fields.find((f) => f._key === pathKey), documentPresets = !!(documentSchema != null && documentSchema.name) && (presets == null ? void 0 : presets[documentSchema == null ? void 0 : documentSchema.name]), missingPresetInstructions = react.useMemo(() => {
912
- var _a, _b;
913
- if (!documentPresets || !pathKey)
914
- return;
915
- const existingInstructions = existingField == null ? void 0 : existingField.instructions, presetField = (_a = documentPresets.fields) == null ? void 0 : _a.find((f) => f.path === pathKey);
916
- return (_b = presetField == null ? void 0 : presetField.instructions) == null ? void 0 : _b.filter(
917
- (i) => !(existingInstructions != null && existingInstructions.some((ei) => ei._key === i._key))
918
- );
919
- }, [documentPresets, pathKey, existingField]), initialized = react.useRef(!1);
920
- return react.useEffect(() => {
921
- var _a;
922
- if (initialized.current || !pathKey || existingField && !(missingPresetInstructions != null && missingPresetInstructions.length))
923
- return;
924
- let event = sanity.PatchEvent.from([sanity.setIfMissing([], ["fields"])]);
925
- existingField || (event = event.append(
926
- sanity.insert(
927
- [
928
- sanity.typed({
929
- _key: pathKey,
930
- _type: assistFieldTypeName,
931
- path: pathKey,
932
- instructions: []
933
- })
934
- ],
935
- "after",
936
- ["fields", -1]
937
- )
938
- )), (_a = existingField == null ? void 0 : existingField.instructions) != null && _a.length || (event = event.append([sanity.setIfMissing([], ["fields", { _key: pathKey }, "instructions"])])), missingPresetInstructions != null && missingPresetInstructions.length && (event = event.append(
939
- sanity.insert(
940
- missingPresetInstructions.map(
941
- (preset) => {
942
- var _a2;
943
- return {
944
- ...preset,
945
- _type: "sanity.assist.instruction",
946
- prompt: (_a2 = preset.prompt) == null ? void 0 : _a2.map((p) => ({ markDefs: [], ...p }))
947
- };
948
- }
949
- ),
950
- "after",
951
- ["fields", { _key: pathKey }, "instructions", -1]
952
- )
953
- )), onChange(event), initialized.current = !0;
954
- }, [activePath, onChange, pathKey, existingField, missingPresetInstructions]), null;
955
- }
956
- function useDocumentState(id, docType) {
957
- const state = sanity.useEditState(id, docType);
958
- return state.draft || state.published;
959
- }
960
- function useStudioAssistDocument({
961
- documentId,
962
- schemaType,
963
- initDoc
964
- }) {
965
- const documentTypeName = schemaType.name, currentUser = sanity.useCurrentUser(), assistDocument = useDocumentState(
966
- assistDocumentId(documentTypeName),
967
- assistDocumentTypeName
968
- ), assistTasksStatus = useDocumentState(
969
- assistTasksStatusId(documentId != null ? documentId : ""),
970
- assistTasksStatusTypeName
971
- ), client = sanity.useClient({ apiVersion: "2023-01-01" });
972
- return react.useEffect(() => {
973
- !assistDocument && initDoc && client.createIfNotExists({
974
- _id: assistDocumentId(documentTypeName),
975
- _type: assistDocumentTypeName
976
- }).catch(() => {
977
- });
978
- }, [client, assistDocument, documentTypeName, initDoc]), react.useMemo(() => {
979
- var _a, _b;
980
- if (!assistDocument)
981
- return;
982
- const tasks = (_a = assistTasksStatus == null ? void 0 : assistTasksStatus.tasks) != null ? _a : [], fields = ((_b = assistDocument == null ? void 0 : assistDocument.fields) != null ? _b : []).map((assistField) => {
983
- var _a2;
984
- return {
985
- ...assistField,
986
- tasks: tasks.filter((task) => task.path === assistField.path),
987
- instructions: (_a2 = assistField.instructions) == null ? void 0 : _a2.filter((p) => !p.userId || p.userId === (currentUser == null ? void 0 : currentUser.id)).map((instruction2) => asStudioInstruction(instruction2, tasks))
988
- };
989
- });
990
- return sanity.typed({
991
- ...assistDocument,
992
- tasks: tasks == null ? void 0 : tasks.map((task) => {
993
- var _a2, _b2;
994
- const instruction2 = (_b2 = (_a2 = fields.find((f) => f.path === task.path)) == null ? void 0 : _a2.instructions) == null ? void 0 : _b2.find((i) => i._key === task.instructionKey);
995
- return {
996
- ...task,
997
- instruction: instruction2
998
- };
999
- }),
1000
- fields
1001
- });
1002
- }, [assistDocument, assistTasksStatus, currentUser]);
1003
- }
1004
- function asStudioInstruction(instruction2, run) {
1005
- return {
1006
- ...instruction2,
1007
- tasks: run.filter((task) => task.instructionKey === instruction2._key).filter(
1008
- (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
1009
- )
1010
- };
1011
- }
1012
- function usePathKey(path) {
1013
- return react.useMemo(() => getPathKey(path), [path]);
1014
- }
1015
- function getPathKey(path) {
1016
- return path.length ? Array.isArray(path) ? sanity.pathToString(path) : path : documentRootKey;
1017
- }
1018
- function getInstructionTitle(instruction2) {
1019
- var _a;
1020
- return (_a = instruction2 == null ? void 0 : instruction2.title) != null ? _a : "Untitled";
756
+ statusLoading,
757
+ init,
758
+ initLoading,
759
+ error
760
+ }), [config, status, init, statusLoading, initLoading, error]);
761
+ return /* @__PURE__ */ jsxRuntime.jsx(AiAssistanceConfigContext.Provider, { value: context, children });
1021
762
  }
1022
763
  const NO_INPUT = {}, RunInstructionContext = react.createContext({
1023
764
  runInstruction: () => {
@@ -1194,7 +935,7 @@ function getConditionalMembers(docState) {
1194
935
  path: "",
1195
936
  hidden: !1,
1196
937
  readOnly: !!docState.readOnly,
1197
- conditional: typeof docState.schemaType.hidden == "function"
938
+ conditional: isConditional(docState.schemaType)
1198
939
  }, ...extractConditionalPaths(docState, MAX_DEPTH)].filter((v) => v.conditional).map(({ conditional, ...state }) => ({ ...state }));
1199
940
  }
1200
941
  function isConditional(schemaType) {
@@ -1294,6 +1035,101 @@ function useOnboardingFeature(featureKey) {
1294
1035
  }, [setShowOnboarding, featureKey]);
1295
1036
  return { showOnboarding, dismissOnboarding };
1296
1037
  }
1038
+ const SelectedFieldContext = react.createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, maxDepth = 6;
1039
+ function getTypeIcon(schemaType) {
1040
+ let t = schemaType;
1041
+ for (; t; ) {
1042
+ if (t.icon)
1043
+ return t.icon;
1044
+ t = t.type;
1045
+ }
1046
+ return isType(schemaType, "slug") ? icons.LinkIcon : isType(schemaType, "image") ? icons.ImageIcon : schemaType.jsonType === "array" && isPortableTextArray(schemaType) ? icons.BlockContentIcon : schemaType.jsonType === "array" ? icons.OlistIcon : schemaType.jsonType === "object" ? icons.BlockquoteIcon : schemaType.jsonType === "string" ? icons.StringIcon : icons.DocumentIcon;
1047
+ }
1048
+ function getFieldRefsWithDocument(schemaType) {
1049
+ var _a;
1050
+ const fields = getFieldRefs(schemaType);
1051
+ return [
1052
+ {
1053
+ key: documentRootKey,
1054
+ icon: (_a = schemaType.icon) != null ? _a : icons.DocumentIcon,
1055
+ title: "The entire document",
1056
+ path: [],
1057
+ schemaType
1058
+ },
1059
+ ...fields
1060
+ ];
1061
+ }
1062
+ function getFieldRefs(schemaType, parent, depth = 0) {
1063
+ return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
1064
+ var _a;
1065
+ const path = parent ? [...parent.path, field.name] : [field.name], title = (_a = field.type.title) != null ? _a : field.name, fieldRef = {
1066
+ key: patchableKey(sanity.pathToString(path)),
1067
+ path,
1068
+ title: parent ? [parent.title, title].join(" / ") : title,
1069
+ schemaType: field.type,
1070
+ icon: getTypeIcon(field.type)
1071
+ }, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
1072
+ return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
1073
+ });
1074
+ }
1075
+ function getSyntheticFields(schemaType, parent, depth = 0) {
1076
+ return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
1077
+ var _a;
1078
+ const segment = { _key: itemType.name }, title = (_a = itemType.title) != null ? _a : itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
1079
+ key: patchableKey(sanity.pathToString(path)),
1080
+ path,
1081
+ title: parent ? [parent.title, title].join(" / ") : title,
1082
+ schemaType: itemType,
1083
+ icon: getTypeIcon(itemType),
1084
+ synthetic: !0
1085
+ }, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
1086
+ return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
1087
+ });
1088
+ }
1089
+ function getTypePath(doc, pathString) {
1090
+ if (!pathString)
1091
+ return;
1092
+ const path = sanity.stringToPath(pathString), currentPath = [];
1093
+ let valid = !0;
1094
+ const syntheticPath = path.map((segment) => {
1095
+ if (currentPath.push(segment), sanity.isKeySegment(segment)) {
1096
+ const match = mutator.extractWithPath(sanity.pathToString(currentPath), doc)[0], value = match == null ? void 0 : match.value;
1097
+ if (match && value && typeof value == "object" && "_type" in value)
1098
+ return { _key: value._type };
1099
+ valid = !1;
1100
+ }
1101
+ return segment;
1102
+ });
1103
+ return valid ? patchableKey(sanity.pathToString(syntheticPath)) : void 0;
1104
+ }
1105
+ function patchableKey(pathKey) {
1106
+ return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
1107
+ }
1108
+ function useTypePath(doc, pathString) {
1109
+ return react.useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
1110
+ }
1111
+ function useSelectedField(documentSchemaType, path) {
1112
+ const selectableFields = react.useMemo(
1113
+ () => documentSchemaType && sanity.isObjectSchemaType(documentSchemaType) ? getFieldRefsWithDocument(documentSchemaType) : [],
1114
+ [documentSchemaType]
1115
+ );
1116
+ return react.useMemo(() => path ? selectableFields == null ? void 0 : selectableFields.find((f) => f.key === path) : void 0, [selectableFields, path]);
1117
+ }
1118
+ function getFieldTitle(field) {
1119
+ var _a, _b, _c;
1120
+ const schemaType = field == null ? void 0 : field.schemaType;
1121
+ return (_c = (_b = (_a = field == null ? void 0 : field.title) != null ? _a : schemaType == null ? void 0 : schemaType.title) != null ? _b : schemaType == null ? void 0 : schemaType.name) != null ? _c : "Untitled";
1122
+ }
1123
+ function useAiPaneRouter() {
1124
+ const paneRouter = structure.usePaneRouter();
1125
+ return react.useMemo(
1126
+ () => {
1127
+ var _a;
1128
+ return { ...paneRouter, params: (_a = paneRouter.params) != null ? _a : {} };
1129
+ },
1130
+ [paneRouter]
1131
+ );
1132
+ }
1297
1133
  function FieldAutocomplete(props) {
1298
1134
  const { id, schemaType, fieldPath, onSelect, includeDocument, filter } = props, fieldRefs = react.useMemo(() => includeDocument ? getFieldRefsWithDocument(schemaType) : getFieldRefs(schemaType), [schemaType, includeDocument]), currentField = react.useMemo(
1299
1135
  () => fieldRefs.find((f) => f.key === fieldPath),
@@ -1473,6 +1309,7 @@ const TASK_STATUS_BUTTON_TOOLTIP_PROPS = {
1473
1309
  sanity.StatusButton,
1474
1310
  {
1475
1311
  label: `${pluginTitle} status`,
1312
+ "aria-label": `${pluginTitle} status`,
1476
1313
  icon: isRunning ? SyncSpinningIcon : hasErrors ? icons.ErrorOutlineIcon : icons.CheckmarkCircleIcon,
1477
1314
  mode: "bleed",
1478
1315
  onClick,
@@ -1684,7 +1521,7 @@ function AssistInspector(props) {
1684
1521
  conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
1685
1522
  }),
1686
1523
  [pathKey, instruction2, typePath, documentType, assistableDocId, requestRunInstruction]
1687
- ), Region = react.useCallback((_props) => /* @__PURE__ */ jsxRuntime.jsx("div", { ..._props, style: { height: "100%", flex: 1, overflow: "auto" } }), []);
1524
+ ), Region = react.useCallback((_props) => /* @__PURE__ */ jsxRuntime.jsx("div", { ..._props, style: { height: "100%", flex: 1, overflow: "auto" } }), []), assistTypeContext = react.useMemo(() => ({ typePath, documentType }), [typePath, documentType]);
1688
1525
  return !documentId || !schemaType || schemaType.jsonType !== "object" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { flex: 1, padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Document not ready yet." }) }) : /* @__PURE__ */ jsxRuntime.jsxs(
1689
1526
  ui.Flex,
1690
1527
  {
@@ -1704,7 +1541,7 @@ function AssistInspector(props) {
1704
1541
  }
1705
1542
  ),
1706
1543
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { as: Region, flex: 1, overflow: "auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", style: { minHeight: "100%" }, children: [
1707
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.PresenceOverlay, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 4, children: selectedField && /* @__PURE__ */ jsxRuntime.jsx(TypePathContext.Provider, { value: typePath, children: /* @__PURE__ */ jsxRuntime.jsx(
1544
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.PresenceOverlay, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 4, children: selectedField && /* @__PURE__ */ jsxRuntime.jsx(AssistTypeContext.Provider, { value: assistTypeContext, children: /* @__PURE__ */ jsxRuntime.jsx(
1708
1545
  sanity.VirtualizerScrollInstanceProvider,
1709
1546
  {
1710
1547
  scrollElement: boundary.current,
@@ -1779,7 +1616,7 @@ function AiInspectorHeader(props) {
1779
1616
  showOnboarding && /* @__PURE__ */ jsxRuntime.jsx(InspectorOnboarding, { onDismiss: dismissOnboarding })
1780
1617
  ] });
1781
1618
  }
1782
- const assistInspector = {
1619
+ const aiInspectorId = "ai-assistance", assistInspector = {
1783
1620
  name: aiInspectorId,
1784
1621
  useMenuItem: () => ({
1785
1622
  icon: icons.SparklesIcon,
@@ -2721,6 +2558,163 @@ function AssistItem(props) {
2721
2558
  presence.map((pre) => /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { style: { position: "absolute", right: 35 }, children: /* @__PURE__ */ jsxRuntime.jsx(AiFieldPresence, { presence: pre }) }, pre.user.id))
2722
2559
  ] });
2723
2560
  }
2561
+ function BackToInstructionListLink() {
2562
+ const { openInspector } = structure.useDocumentPane(), goBack = react.useCallback(
2563
+ () => openInspector(aiInspectorId, { [instructionParam]: void 0 }),
2564
+ [openInspector]
2565
+ );
2566
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
2567
+ ui.Button,
2568
+ {
2569
+ as: "a",
2570
+ fontSize: 1,
2571
+ icon: icons.ArrowLeftIcon,
2572
+ mode: "bleed",
2573
+ padding: 1,
2574
+ space: 2,
2575
+ onClick: goBack,
2576
+ text: " Instructions",
2577
+ textAlign: "left"
2578
+ }
2579
+ ) });
2580
+ }
2581
+ const EMPTY_FIELDS = [];
2582
+ function AssistDocumentForm(props) {
2583
+ return props.readOnly ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { border: !0, tone: "caution", padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: " You do not have sufficient permissions to manage instructions." }) }) : /* @__PURE__ */ jsxRuntime.jsx(AssistDocumentFormEditable, { ...props });
2584
+ }
2585
+ function AssistDocumentFormEditable(props) {
2586
+ const { onChange } = props, value = props.value, id = value == null ? void 0 : value._id, fields = value == null ? void 0 : value.fields, { params, setParams } = useAiPaneRouter(), pathKey = params[fieldPathParam], { typePath, documentType: targetDocumentType } = react.useContext(AssistTypeContext), instruction2 = params[instructionParam], activeKey = react.useMemo(() => {
2587
+ var _a;
2588
+ if (typePath)
2589
+ return (_a = (fields != null ? fields : EMPTY_FIELDS).find((f) => f.path === typePath)) == null ? void 0 : _a._key;
2590
+ }, [fields, typePath]), activePath = react.useMemo(() => {
2591
+ if (!activeKey)
2592
+ return;
2593
+ const base = ["fields", { _key: activeKey }];
2594
+ return instruction2 ? [...base, "instructions", { _key: instruction2 }] : base;
2595
+ }, [activeKey, instruction2]), schema = sanity.useSchema(), documentSchema = react.useMemo(() => {
2596
+ if (targetDocumentType)
2597
+ return schema.get(targetDocumentType);
2598
+ }, [schema, targetDocumentType]), fieldSchema = useSelectedSchema(pathKey, documentSchema), context = react.useMemo(
2599
+ () => ({
2600
+ documentSchema,
2601
+ fieldSchema: fieldSchema != null ? fieldSchema : documentSchema
2602
+ }),
2603
+ [fieldSchema, documentSchema]
2604
+ ), title = value == null ? void 0 : value.title;
2605
+ react.useEffect(() => {
2606
+ var _a;
2607
+ !title && documentSchema && !(id != null && id.startsWith("drafts.")) && onChange(sanity.set((_a = documentSchema.title) != null ? _a : documentSchema.name, ["title"]));
2608
+ }, [title, documentSchema, onChange, id]);
2609
+ const { onPathOpen, ...formCallbacks } = sanity.useFormCallbacks(), newCallbacks = react.useMemo(
2610
+ () => ({
2611
+ ...formCallbacks,
2612
+ onPathOpen: (path) => {
2613
+ var _a;
2614
+ !instruction2 && path.length === 4 && path[2] === "instructions" ? (setParams(
2615
+ sanity.typed({
2616
+ ...params,
2617
+ [instructionParam]: (_a = path[3]) == null ? void 0 : _a._key
2618
+ })
2619
+ ), onPathOpen([])) : setTimeout(() => onPathOpen(path), 0);
2620
+ }
2621
+ }),
2622
+ [formCallbacks, onPathOpen, params, setParams, instruction2]
2623
+ );
2624
+ return react.useEffect(() => {
2625
+ activePath && !instruction2 && onPathOpen([]);
2626
+ }, [activePath, instruction2, onPathOpen]), /* @__PURE__ */ jsxRuntime.jsx(SelectedFieldContextProvider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 5, children: [
2627
+ /* @__PURE__ */ jsxRuntime.jsx(
2628
+ FieldsInitializer,
2629
+ {
2630
+ pathKey: typePath,
2631
+ activePath,
2632
+ fields,
2633
+ documentSchema,
2634
+ onChange
2635
+ },
2636
+ typePath
2637
+ ),
2638
+ instruction2 && /* @__PURE__ */ jsxRuntime.jsx(BackToInstructionListLink, {}),
2639
+ activePath && /* @__PURE__ */ jsxRuntime.jsx(sanity.FormCallbacksProvider, { ...newCallbacks, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { lineHeight: "1.25em" }, children: /* @__PURE__ */ jsxRuntime.jsx(sanity.FormInput, { ...props, absolutePath: activePath }) }) }),
2640
+ !activePath && props.renderDefault(props)
2641
+ ] }) });
2642
+ }
2643
+ function useSelectedSchema(fieldPath, documentSchema) {
2644
+ return react.useMemo(() => {
2645
+ if (!fieldPath)
2646
+ return;
2647
+ if (fieldPath === documentRootKey)
2648
+ return documentSchema;
2649
+ const path = sanity.stringToPath(fieldPath);
2650
+ let currentSchema = documentSchema;
2651
+ for (let i = 0; i < path.length; i++) {
2652
+ const segment = path[i], field = currentSchema == null ? void 0 : currentSchema.fields.find((f) => f.name === segment);
2653
+ if (!field)
2654
+ return;
2655
+ if (i === path.length - 1)
2656
+ return field.type;
2657
+ if (field.type.jsonType !== "object")
2658
+ return;
2659
+ currentSchema = field.type;
2660
+ }
2661
+ return currentSchema;
2662
+ }, [documentSchema, fieldPath]);
2663
+ }
2664
+ function FieldsInitializer({
2665
+ pathKey,
2666
+ activePath,
2667
+ fields,
2668
+ documentSchema,
2669
+ onChange
2670
+ }) {
2671
+ const {
2672
+ config: { __presets: presets }
2673
+ } = useAiAssistanceConfig(), existingField = fields == null ? void 0 : fields.find((f) => f._key === pathKey), documentPresets = !!(documentSchema != null && documentSchema.name) && (presets == null ? void 0 : presets[documentSchema == null ? void 0 : documentSchema.name]), missingPresetInstructions = react.useMemo(() => {
2674
+ var _a, _b;
2675
+ if (!documentPresets || !pathKey)
2676
+ return;
2677
+ const existingInstructions = existingField == null ? void 0 : existingField.instructions, presetField = (_a = documentPresets.fields) == null ? void 0 : _a.find((f) => f.path === pathKey);
2678
+ return (_b = presetField == null ? void 0 : presetField.instructions) == null ? void 0 : _b.filter(
2679
+ (i) => !(existingInstructions != null && existingInstructions.some((ei) => ei._key === i._key))
2680
+ );
2681
+ }, [documentPresets, pathKey, existingField]), initialized = react.useRef(!1);
2682
+ return react.useEffect(() => {
2683
+ var _a;
2684
+ if (initialized.current || !pathKey || existingField && !(missingPresetInstructions != null && missingPresetInstructions.length))
2685
+ return;
2686
+ let event = sanity.PatchEvent.from([sanity.setIfMissing([], ["fields"])]);
2687
+ existingField || (event = event.append(
2688
+ sanity.insert(
2689
+ [
2690
+ sanity.typed({
2691
+ _key: pathKey,
2692
+ _type: assistFieldTypeName,
2693
+ path: pathKey,
2694
+ instructions: []
2695
+ })
2696
+ ],
2697
+ "after",
2698
+ ["fields", -1]
2699
+ )
2700
+ )), (_a = existingField == null ? void 0 : existingField.instructions) != null && _a.length || (event = event.append([sanity.setIfMissing([], ["fields", { _key: pathKey }, "instructions"])])), missingPresetInstructions != null && missingPresetInstructions.length && (event = event.append(
2701
+ sanity.insert(
2702
+ missingPresetInstructions.map(
2703
+ (preset) => {
2704
+ var _a2;
2705
+ return {
2706
+ ...preset,
2707
+ _type: "sanity.assist.instruction",
2708
+ prompt: (_a2 = preset.prompt) == null ? void 0 : _a2.map((p) => ({ markDefs: [], ...p }))
2709
+ };
2710
+ }
2711
+ ),
2712
+ "after",
2713
+ ["fields", { _key: pathKey }, "instructions", -1]
2714
+ )
2715
+ )), onChange(event), initialized.current = !0;
2716
+ }, [activePath, onChange, pathKey, existingField, missingPresetInstructions]), null;
2717
+ }
2724
2718
  const InlineBlockValueContext = react.createContext(void 0);
2725
2719
  function AssistInlineFormBlock(props) {
2726
2720
  return /* @__PURE__ */ jsxRuntime.jsx(InlineBlockValueContext.Provider, { value: props.value, children: /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.renderDefault(props) }) });
@@ -2786,7 +2780,7 @@ function InstructionVisibility(props) {
2786
2780
  }
2787
2781
  function FieldRefPathInput(props) {
2788
2782
  var _a;
2789
- const documentSchema = (_a = react.useContext(SelectedFieldContext)) == null ? void 0 : _a.documentSchema, typePath = react.useContext(TypePathContext), ref = react.useRef(null), id = react.useId(), { onChange } = props;
2783
+ const documentSchema = (_a = react.useContext(SelectedFieldContext)) == null ? void 0 : _a.documentSchema, { typePath } = react.useContext(AssistTypeContext), ref = react.useRef(null), id = react.useId(), { onChange } = props;
2790
2784
  react.useEffect(() => {
2791
2785
  var _a2, _b;
2792
2786
  (_b = (_a2 = ref.current) == null ? void 0 : _a2.querySelector("input")) == null || _b.focus();