@sanity/assist 1.0.11 → 1.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/dist/index.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7, _templateObject8, _templateObject9, _templateObject10, _templateObject11, _templateObject12;
4
- function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
5
3
  Object.defineProperty(exports, '__esModule', {
6
4
  value: true
7
5
  });
@@ -71,7 +69,7 @@ const listenQuery = function (client, query) {
71
69
  const events$ = listen(client, listenerQuery, params, options).pipe(operators.mergeMap((ev, i) => {
72
70
  const isFirst = i === 0;
73
71
  if (isFirst && !isWelcomeEvent(ev)) {
74
- return rxjs.throwError(new Error(ev.type === "reconnect" ? "Could not establish EventSource connection" : "Received unexpected type of first event \"".concat(ev.type, "\"")));
72
+ return rxjs.throwError(new Error(ev.type === "reconnect" ? "Could not establish EventSource connection" : 'Received unexpected type of first event "'.concat(ev.type, '"')));
75
73
  }
76
74
  return rxjs.of(ev);
77
75
  }), operators.share());
@@ -135,6 +133,20 @@ function isType(schemaType, typeName) {
135
133
  }
136
134
  return isType(schemaType.type, typeName);
137
135
  }
136
+ function isImage(schemaType) {
137
+ return isType(schemaType, "image");
138
+ }
139
+ function getCaptionFieldOption(schemaType) {
140
+ var _a;
141
+ if (!schemaType) {
142
+ return void 0;
143
+ }
144
+ const captionField = (_a = schemaType.options) == null ? void 0 : _a.captionField;
145
+ if (captionField) {
146
+ return captionField;
147
+ }
148
+ return getCaptionFieldOption(schemaType.type);
149
+ }
138
150
  function isSchemaAssistEnabled(type) {
139
151
  var _a, _b;
140
152
  return !((_b = (_a = type.options) == null ? void 0 : _a.aiWritingAssistance) == null ? void 0 : _b.exclude);
@@ -697,8 +709,14 @@ function getInstructionTitle(instruction) {
697
709
  var _a;
698
710
  return (_a = instruction == null ? void 0 : instruction.title) != null ? _a : "Untitled";
699
711
  }
700
- const rotate = styled.keyframes(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n 0% {\n transform: rotate(0);\n }\n 100% {\n transform: rotate(360deg);\n }\n"])));
701
- const SyncSpinningIcon = styled__default.default(icons.SyncIcon)(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n animation: ", " 1s linear infinite;\n"])), rotate);
712
+ var __freeze$5 = Object.freeze;
713
+ var __defProp$5 = Object.defineProperty;
714
+ var __template$5 = (cooked, raw) => __freeze$5(__defProp$5(cooked, "raw", {
715
+ value: __freeze$5(raw || cooked.slice())
716
+ }));
717
+ var _a$5, _b$3;
718
+ const rotate = styled.keyframes(_a$5 || (_a$5 = __template$5(["\n 0% {\n transform: rotate(0);\n }\n 100% {\n transform: rotate(360deg);\n }\n"])));
719
+ const SyncSpinningIcon = styled__default.default(icons.SyncIcon)(_b$3 || (_b$3 = __template$5(["\n animation: ", " 1s linear infinite;\n"])), rotate);
702
720
  const TASK_CONFIG = {
703
721
  aborted: {
704
722
  title: "Canceled",
@@ -736,25 +754,26 @@ function InstructionTaskHistoryButton(props) {
736
754
  return;
737
755
  }
738
756
  const statusDocId = assistTasksStatusId(documentId);
739
- const basePath = "".concat(sanity.typed("tasks"), "[_key==\"").concat(taskKey, "\"]");
757
+ const basePath = "".concat(sanity.typed("tasks"), '[_key=="').concat(taskKey, '"]');
740
758
  client.patch(statusDocId).set({
741
759
  ["".concat(basePath, ".").concat(sanity.typed("ended"))]: /* @__PURE__ */new Date().toISOString(),
742
760
  ["".concat(basePath, ".").concat(sanity.typed("reason"))]: sanity.typed("aborted")
743
761
  }).commit().catch(console.error);
744
762
  }, [client, documentId]);
745
763
  const titledTasks = react.useMemo(() => {
746
- var _a;
747
- const t = (_a = tasks == null ? void 0 : tasks.filter(task => task.started && /* @__PURE__ */new Date().getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs).map(task => {
764
+ var _a2;
765
+ const t = (_a2 = tasks == null ? void 0 : tasks.filter(task => task.started && /* @__PURE__ */new Date().getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs).map(task => {
766
+ var _a3;
748
767
  const instruction = instructions == null ? void 0 : instructions.find(i => i._key === task.instructionKey);
749
768
  return {
750
769
  ...task,
751
- title: showTitles ? getInstructionTitle(instruction) : void 0,
770
+ title: showTitles ? (_a3 = task.title) != null ? _a3 : getInstructionTitle(instruction) : void 0,
752
771
  cancel: () => cancelRun(task._key)
753
772
  };
754
- })) != null ? _a : [];
773
+ })) != null ? _a2 : [];
755
774
  t.sort((a, b) => {
756
- var _a2, _b;
757
- return new Date((_a2 = b.started) != null ? _a2 : "").getTime() - new Date((_b = a.started) != null ? _b : "").getTime();
775
+ var _a3, _b2;
776
+ return new Date((_a3 = b.started) != null ? _a3 : "").getTime() - new Date((_b2 = a.started) != null ? _b2 : "").getTime();
758
777
  });
759
778
  return t;
760
779
  }, [tasks, instructions, cancelRun, showTitles]);
@@ -839,7 +858,7 @@ function TaskList(props) {
839
858
  });
840
859
  }
841
860
  function TaskItem(props) {
842
- var _a;
861
+ var _a2;
843
862
  const {
844
863
  task
845
864
  } = props;
@@ -877,7 +896,7 @@ function TaskItem(props) {
877
896
  muted: true,
878
897
  size: 1,
879
898
  children: /* @__PURE__ */jsxRuntime.jsx(TimeAgo, {
880
- date: (_a = task.ended) != null ? _a : task.started
899
+ date: (_a2 = task.ended) != null ? _a2 : task.started
881
900
  })
882
901
  })]
883
902
  })]
@@ -902,6 +921,48 @@ function useApiClient(customApiClient) {
902
921
  });
903
922
  return react.useMemo(() => customApiClient ? customApiClient(client) : client, [client, customApiClient]);
904
923
  }
924
+ function useGenerateCaption(apiClient) {
925
+ const [loading, setLoading] = react.useState(false);
926
+ const user = sanity.useCurrentUser();
927
+ const schema = sanity.useSchema();
928
+ const types = react.useMemo(() => serializeSchema(schema, {
929
+ leanFormat: true
930
+ }), [schema]);
931
+ const toast = ui.useToast();
932
+ const generateCaption = react.useCallback(_ref4 => {
933
+ let {
934
+ path,
935
+ documentId
936
+ } = _ref4;
937
+ setLoading(true);
938
+ return apiClient.request({
939
+ method: "POST",
940
+ url: "/assist/tasks/generate-caption/".concat(apiClient.config().dataset, "?projectId=").concat(apiClient.config().projectId),
941
+ body: {
942
+ path,
943
+ documentId,
944
+ types,
945
+ userId: user == null ? void 0 : user.id
946
+ }
947
+ }).catch(e => {
948
+ toast.push({
949
+ status: "error",
950
+ title: "Generate caption failed",
951
+ description: e.message
952
+ });
953
+ setLoading(false);
954
+ throw e;
955
+ }).finally(() => {
956
+ setTimeout(() => {
957
+ setLoading(false);
958
+ }, 2e3);
959
+ });
960
+ }, [setLoading, apiClient, toast, user, types]);
961
+ return react.useMemo(() => ({
962
+ generateCaption,
963
+ loading
964
+ }), [generateCaption, loading]);
965
+ }
905
966
  function useGetInstructStatus(apiClient) {
906
967
  const [loading, setLoading] = react.useState(true);
907
968
  const projectClient = sanity.useClient({
@@ -1102,8 +1163,8 @@ function RunInstructionProvider(props) {
1102
1163
  runInstructionRequest({
1103
1164
  ...request,
1104
1165
  instructionKey: instruction._key,
1105
- userTexts: Object.entries(inputs).map(_ref4 => {
1106
- let [key, value] = _ref4;
1166
+ userTexts: Object.entries(inputs).map(_ref5 => {
1167
+ let [key, value] = _ref5;
1107
1168
  return {
1108
1169
  blockKey: key,
1109
1170
  userInput: value
@@ -1116,8 +1177,8 @@ function RunInstructionProvider(props) {
1116
1177
  const open = !!runRequest;
1117
1178
  const runDisabled = react.useMemo(() => {
1118
1179
  var _a2, _b;
1119
- return ((_b = (_a2 = runRequest == null ? void 0 : runRequest.userInputBlocks) == null ? void 0 : _a2.length) != null ? _b : 0) > Object.entries(inputs).filter(_ref5 => {
1120
- let [, value] = _ref5;
1180
+ return ((_b = (_a2 = runRequest == null ? void 0 : runRequest.userInputBlocks) == null ? void 0 : _a2.length) != null ? _b : 0) > Object.entries(inputs).filter(_ref6 => {
1181
+ let [, value] = _ref6;
1121
1182
  return !!value;
1122
1183
  }).length;
1123
1184
  }, [runRequest == null ? void 0 : runRequest.userInputBlocks, inputs]);
@@ -1329,8 +1390,14 @@ function useOnboardingFeature(featureKey) {
1329
1390
  dismissOnboarding
1330
1391
  };
1331
1392
  }
1332
- const CardWithShadowBelow = styled__default.default(ui.Card)(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n position: relative;\n\n &:after {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 0;\n bottom: -1px;\n border-bottom: 1px solid var(--card-border-color);\n opacity: 0.5;\n z-index: 100;\n }\n"])));
1333
- const CardWithShadowAbove = styled__default.default(ui.Card)(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n position: relative;\n\n &:after {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 0;\n top: -1px;\n border-top: 1px solid var(--card-border-color);\n opacity: 0.5;\n z-index: 100;\n }\n"])));
1393
+ var __freeze$4 = Object.freeze;
1394
+ var __defProp$4 = Object.defineProperty;
1395
+ var __template$4 = (cooked, raw) => __freeze$4(__defProp$4(cooked, "raw", {
1396
+ value: __freeze$4(raw || cooked.slice())
1397
+ }));
1398
+ var _a$4, _b$2;
1399
+ const CardWithShadowBelow = styled__default.default(ui.Card)(_a$4 || (_a$4 = __template$4(["\n position: relative;\n\n &:after {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 0;\n bottom: -1px;\n border-bottom: 1px solid var(--card-border-color);\n opacity: 0.5;\n z-index: 100;\n }\n"])));
1400
+ const CardWithShadowAbove = styled__default.default(ui.Card)(_b$2 || (_b$2 = __template$4(["\n position: relative;\n\n &:after {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 0;\n top: -1px;\n border-top: 1px solid var(--card-border-color);\n opacity: 0.5;\n z-index: 100;\n }\n"])));
1334
1401
  function AssistInspectorWrapper(props) {
1335
1402
  const context = useAiAssistanceConfig();
1336
1403
  if (context.statusLoading) {
@@ -1449,11 +1516,11 @@ function AssistInspectorWrapper(props) {
1449
1516
  });
1450
1517
  }
1451
1518
  function AssistInspector(props) {
1452
- var _a, _b;
1519
+ var _a2, _b2;
1453
1520
  const {
1454
1521
  params
1455
1522
  } = useAiPaneRouter();
1456
- const [boundary, setBoundary] = react.useState(null);
1523
+ const boundary = react.useRef(null);
1457
1524
  const pathKey = params == null ? void 0 : params[fieldPathParam];
1458
1525
  const instructionKey = params == null ? void 0 : params[instructionParam];
1459
1526
  const documentPane = desk.useDocumentPane();
@@ -1481,28 +1548,28 @@ function AssistInspector(props) {
1481
1548
  documentId,
1482
1549
  schemaType
1483
1550
  });
1484
- const assistField = (_a = assistDocument == null ? void 0 : assistDocument.fields) == null ? void 0 : _a.find(f => f.path === pathKey);
1485
- const instruction = (_b = assistField == null ? void 0 : assistField.instructions) == null ? void 0 : _b.find(i => i._key === instructionKey);
1551
+ const assistField = (_a2 = assistDocument == null ? void 0 : assistDocument.fields) == null ? void 0 : _a2.find(f => f.path === pathKey);
1552
+ const instruction = (_b2 = assistField == null ? void 0 : assistField.instructions) == null ? void 0 : _b2.find(i => i._key === instructionKey);
1486
1553
  const tasks = react.useMemo(() => {
1487
- var _a2;
1488
- return (_a2 = assistDocument == null ? void 0 : assistDocument.tasks) == null ? void 0 : _a2.filter(i => !instructionKey || i.instructionKey === instructionKey);
1554
+ var _a3;
1555
+ return (_a3 = assistDocument == null ? void 0 : assistDocument.tasks) == null ? void 0 : _a3.filter(i => !instructionKey || i.instructionKey === instructionKey);
1489
1556
  }, [assistDocument == null ? void 0 : assistDocument.tasks, instructionKey]);
1490
1557
  const instructions = react.useMemo(() => {
1491
- var _a2;
1492
- return (_a2 = assistDocument == null ? void 0 : assistDocument.fields) == null ? void 0 : _a2.flatMap(f => {
1493
- var _a3;
1494
- return (_a3 = f.instructions) != null ? _a3 : [];
1558
+ var _a3;
1559
+ return (_a3 = assistDocument == null ? void 0 : assistDocument.fields) == null ? void 0 : _a3.flatMap(f => {
1560
+ var _a4;
1561
+ return (_a4 = f.instructions) != null ? _a4 : [];
1495
1562
  });
1496
1563
  }, [assistDocument == null ? void 0 : assistDocument.fields]);
1497
1564
  const promptValue = instruction == null ? void 0 : instruction.prompt;
1498
1565
  const isEmptyPrompt = react.useMemo(() => {
1499
- var _a2, _b2;
1566
+ var _a3, _b3;
1500
1567
  if (!(promptValue == null ? void 0 : promptValue.length)) {
1501
1568
  return true;
1502
1569
  }
1503
1570
  const firstBlock = promptValue[0];
1504
1571
  const children = firstBlock == null ? void 0 : firstBlock.children;
1505
- return promptValue.length == 1 && (children == null ? void 0 : children.length) === 1 && !((_b2 = (_a2 = children == null ? void 0 : children[0]) == null ? void 0 : _a2.text) == null ? void 0 : _b2.length);
1572
+ return promptValue.length == 1 && (children == null ? void 0 : children.length) === 1 && !((_b3 = (_a3 = children == null ? void 0 : children[0]) == null ? void 0 : _a3.text) == null ? void 0 : _b3.length);
1506
1573
  }, [promptValue]);
1507
1574
  const paneNode = react.useMemo(() => ({
1508
1575
  type: "document",
@@ -1539,7 +1606,7 @@ function AssistInspector(props) {
1539
1606
  });
1540
1607
  }
1541
1608
  return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
1542
- ref: setBoundary,
1609
+ ref: boundary,
1543
1610
  direction: "column",
1544
1611
  height: "fill",
1545
1612
  overflow: "hidden",
@@ -1565,7 +1632,8 @@ function AssistInspector(props) {
1565
1632
  children: /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
1566
1633
  padding: 4,
1567
1634
  children: selectedField && /* @__PURE__ */jsxRuntime.jsx(sanity.VirtualizerScrollInstanceProvider, {
1568
- scrollElement: boundary,
1635
+ scrollElement: boundary.current,
1636
+ containerElement: boundary,
1569
1637
  children: /* @__PURE__ */jsxRuntime.jsx(desk.DocumentPaneProvider, {
1570
1638
  paneKey: documentPane.paneKey,
1571
1639
  index: documentPane.index,
@@ -1690,10 +1758,10 @@ const assistInspector = {
1690
1758
  showAsAction: false
1691
1759
  }),
1692
1760
  component: AssistInspectorWrapper,
1693
- onClose(_ref6) {
1761
+ onClose(_ref7) {
1694
1762
  let {
1695
1763
  params
1696
- } = _ref6;
1764
+ } = _ref7;
1697
1765
  return {
1698
1766
  params: sanity.typed({
1699
1767
  ...params,
@@ -1758,20 +1826,27 @@ function aiPresence(presence, path, title) {
1758
1826
  lastActiveAt: (_a = presence == null ? void 0 : presence.started) != null ? _a : /* @__PURE__ */new Date().toISOString()
1759
1827
  };
1760
1828
  }
1761
- const fadeIn = styled.keyframes(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n 0% {\n opacity: 0;\n transform: scale(0.75);\n }\n 40% {\n opacity: 0;\n transform: scale(0.75);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n"])));
1762
- const FadeInDiv = styled__default.default.div(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n animation-name: ", ";\n animation-timing-function: ease-in-out;\n"])), fadeIn);
1763
- function FadeInContent(_ref7) {
1829
+ var __freeze$3 = Object.freeze;
1830
+ var __defProp$3 = Object.defineProperty;
1831
+ var __template$3 = (cooked, raw) => __freeze$3(__defProp$3(cooked, "raw", {
1832
+ value: __freeze$3(raw || cooked.slice())
1833
+ }));
1834
+ var _a$3, _b$1;
1835
+ const fadeIn = styled.keyframes(_a$3 || (_a$3 = __template$3(["\n 0% {\n opacity: 0;\n transform: scale(0.75);\n }\n 40% {\n opacity: 0;\n transform: scale(0.75);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n"])));
1836
+ const FadeInDiv = styled__default.default.div(_b$1 || (_b$1 = __template$3(["\n animation-name: ", ";\n animation-timing-function: ease-in-out;\n"])), fadeIn);
1837
+ const FadeInContent = react.forwardRef(function FadeInContent2(_ref8, ref) {
1764
1838
  let {
1765
1839
  children,
1766
1840
  durationMs = 250
1767
- } = _ref7;
1841
+ } = _ref8;
1768
1842
  return /* @__PURE__ */jsxRuntime.jsx(FadeInDiv, {
1843
+ ref,
1769
1844
  style: {
1770
1845
  animationDuration: "".concat(durationMs, "ms")
1771
1846
  },
1772
1847
  children
1773
1848
  });
1774
- }
1849
+ });
1775
1850
  const purple = {
1776
1851
  "50": {
1777
1852
  title: "Purple 50",
@@ -1818,10 +1893,16 @@ const purple = {
1818
1893
  hex: "#211229"
1819
1894
  }
1820
1895
  };
1821
- const Root = styled__default.default.span(_templateObject7 || (_templateObject7 = _taggedTemplateLiteral(["\n display: block;\n width: 25px;\n height: 25px;\n position: relative;\n"])));
1822
- const dash = styled.keyframes(_templateObject8 || (_templateObject8 = _taggedTemplateLiteral(["\n 0% {\n transform: rotate(0);\n }\n 100% {\n transform: rotate(43deg);\n }\n"])));
1823
- const Outline = styled__default.default.svg(_templateObject9 || (_templateObject9 = _taggedTemplateLiteral(["\n display: block;\n position: absolute;\n top: 0;\n left: 0;\n\n & > circle {\n stroke: var(--ai-avatar-stroke-color);\n stroke-width: 1.5px;\n stroke-linecap: round;\n transform-origin: center;\n animation: ", " 500ms ease-in-out infinite;\n transition: stroke-dasharray 200ms ease-in-out;\n\n stroke-dasharray: 2.34px 0;\n\n [data-state='active'] > & {\n stroke-dasharray: 2px 2.34px;\n }\n }\n"])), dash);
1824
- const IconDisc = styled__default.default.span(_templateObject10 || (_templateObject10 = _taggedTemplateLiteral(["\n background: var(--ai-avatar-disc-color);\n color: white;\n width: 21px;\n height: 21px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10.5px;\n position: absolute;\n top: 2px;\n left: 2px;\n"])));
1896
+ var __freeze$2 = Object.freeze;
1897
+ var __defProp$2 = Object.defineProperty;
1898
+ var __template$2 = (cooked, raw) => __freeze$2(__defProp$2(cooked, "raw", {
1899
+ value: __freeze$2(raw || cooked.slice())
1900
+ }));
1901
+ var _a$2, _b, _c, _d;
1902
+ const Root = styled__default.default.span(_a$2 || (_a$2 = __template$2(["\n display: block;\n width: 25px;\n height: 25px;\n position: relative;\n"])));
1903
+ const dash = styled.keyframes(_b || (_b = __template$2(["\n 0% {\n transform: rotate(0);\n }\n 100% {\n transform: rotate(43deg);\n }\n"])));
1904
+ const Outline = styled__default.default.svg(_c || (_c = __template$2(["\n display: block;\n position: absolute;\n top: 0;\n left: 0;\n\n & > circle {\n stroke: var(--ai-avatar-stroke-color);\n stroke-width: 1.5px;\n stroke-linecap: round;\n transform-origin: center;\n animation: ", " 500ms ease-in-out infinite;\n transition: stroke-dasharray 200ms ease-in-out;\n\n stroke-dasharray: 2.34px 0;\n\n [data-state='active'] > & {\n stroke-dasharray: 2px 2.34px;\n }\n }\n"])), dash);
1905
+ const IconDisc = styled__default.default.span(_d || (_d = __template$2(["\n background: var(--ai-avatar-disc-color);\n color: white;\n width: 21px;\n height: 21px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10.5px;\n position: absolute;\n top: 2px;\n left: 2px;\n"])));
1825
1906
  function AssistAvatar(props) {
1826
1907
  const {
1827
1908
  state = "present"
@@ -2539,7 +2620,7 @@ function AlphaMigration() {
2539
2620
  });
2540
2621
  react.useEffect(() => {
2541
2622
  let canUpdate = true;
2542
- client.fetch("\n {\n \"assistDocs\": *[_type==\"".concat(legacyAssistDocumentTypeName, "\"],\n \"staleStatusDocIds\": *[_type==\"").concat(legacyAssistStatusDocumentTypeName, "\"]._id,\n \"contextDocs\": *[_type==\"").concat(legacyContextDocumentTypeName, "\"],\n }\n ")).then(result => {
2623
+ client.fetch('\n {\n "assistDocs": *[_type=="'.concat(legacyAssistDocumentTypeName, '"],\n "staleStatusDocIds": *[_type=="').concat(legacyAssistStatusDocumentTypeName, '"]._id,\n "contextDocs": *[_type=="').concat(legacyContextDocumentTypeName, '"],\n }\n ')).then(result => {
2543
2624
  var _a, _b, _c;
2544
2625
  if (!canUpdate || !result) {
2545
2626
  return;
@@ -2661,7 +2742,7 @@ async function convertDocs(client, docs, updateProgress) {
2661
2742
  const progressCount = Math.min(docs.length, i + chunkSize);
2662
2743
  const chunk = docs.slice(i, progressCount);
2663
2744
  const trans = client.transaction();
2664
- const contextDocs = await client.fetch("*[_type==\"".concat(contextDocumentTypeName, "\" && _alphaId != null]{_id, _alphaId}"));
2745
+ const contextDocs = await client.fetch('*[_type=="'.concat(contextDocumentTypeName, '" && _alphaId != null]{_id, _alphaId}'));
2665
2746
  chunk.forEach(oldDoc => {
2666
2747
  var _a;
2667
2748
  const documentType = oldDoc._id.replace(new RegExp("^(".concat(legacyAssistDocumentIdPrefix, "|").concat(assistDocumentIdPrefix, ")")), "");
@@ -2769,7 +2850,13 @@ function AssistLayout(props) {
2769
2850
  })]
2770
2851
  });
2771
2852
  }
2772
- const WrapPreCard = styled__default.default(ui.Card)(_templateObject11 || (_templateObject11 = _taggedTemplateLiteral(["\n & pre {\n white-space: pre-wrap !important;\n }\n"])));
2853
+ var __freeze$1 = Object.freeze;
2854
+ var __defProp$1 = Object.defineProperty;
2855
+ var __template$1 = (cooked, raw) => __freeze$1(__defProp$1(cooked, "raw", {
2856
+ value: __freeze$1(raw || cooked.slice())
2857
+ }));
2858
+ var _a$1;
2859
+ const WrapPreCard = styled__default.default(ui.Card)(_a$1 || (_a$1 = __template$1(["\n & pre {\n white-space: pre-wrap !important;\n }\n"])));
2773
2860
  function SafeValueInput(props) {
2774
2861
  return /* @__PURE__ */jsxRuntime.jsx(ErrorWrapper, {
2775
2862
  onChange: props.onChange,
@@ -3046,13 +3133,13 @@ function useSelectedSchema(fieldPath, documentSchema) {
3046
3133
  return currentSchema;
3047
3134
  }, [documentSchema, fieldPath]);
3048
3135
  }
3049
- function FieldsInitializer(_ref8) {
3136
+ function FieldsInitializer(_ref9) {
3050
3137
  let {
3051
3138
  pathKey,
3052
3139
  activePath,
3053
3140
  fieldExists,
3054
3141
  onChange
3055
- } = _ref8;
3142
+ } = _ref9;
3056
3143
  const initialized = react.useRef(false);
3057
3144
  react.useEffect(() => {
3058
3145
  if (initialized.current || fieldExists || activePath || !pathKey) {
@@ -3224,8 +3311,8 @@ function IconInput(props) {
3224
3311
  onChange
3225
3312
  } = props;
3226
3313
  const id = react.useId();
3227
- const items = react.useMemo(() => Object.entries(icons.icons).map(_ref9 => {
3228
- let [key, icon] = _ref9;
3314
+ const items = react.useMemo(() => Object.entries(icons.icons).map(_ref10 => {
3315
+ let [key, icon] = _ref10;
3229
3316
  return /* @__PURE__ */jsxRuntime.jsx(IconItem, {
3230
3317
  iconKey: key,
3231
3318
  icon,
@@ -3253,12 +3340,12 @@ function IconInput(props) {
3253
3340
  }
3254
3341
  });
3255
3342
  }
3256
- function IconItem(_ref10) {
3343
+ function IconItem(_ref11) {
3257
3344
  let {
3258
3345
  icon,
3259
3346
  iconKey: key,
3260
3347
  onChange
3261
- } = _ref10;
3348
+ } = _ref11;
3262
3349
  const onClick = react.useCallback(() => onChange(sanity.set(key)), [onChange, key]);
3263
3350
  return /* @__PURE__ */jsxRuntime.jsx(ui.MenuItem, {
3264
3351
  icon,
@@ -3269,8 +3356,8 @@ function IconItem(_ref10) {
3269
3356
  }
3270
3357
  function getIcon(iconName) {
3271
3358
  var _a, _b;
3272
- return (_b = (_a = Object.entries(icons.icons).find(_ref11 => {
3273
- let [key] = _ref11;
3359
+ return (_b = (_a = Object.entries(icons.icons).find(_ref12 => {
3360
+ let [key] = _ref12;
3274
3361
  return key === iconName;
3275
3362
  })) == null ? void 0 : _a[1]) != null ? _b : icons.icons.sparkles;
3276
3363
  }
@@ -3481,7 +3568,7 @@ function HideReferenceChangedBannerInput(props) {
3481
3568
  const style = document.createElement("style");
3482
3569
  const parentId = "id-".concat(Math.random()).replace(".", "-");
3483
3570
  parent.id = parentId;
3484
- style.innerText = "\n #".concat(parentId, " [data-testid=\"reference-changed-banner\"] { display: none; }\n ");
3571
+ style.innerText = "\n #".concat(parentId, ' [data-testid="reference-changed-banner"] { display: none; }\n ');
3485
3572
  parent.prepend(style);
3486
3573
  }, [ref]);
3487
3574
  return /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
@@ -3524,11 +3611,11 @@ const contextDocumentSchema = sanity.defineType({
3524
3611
  title: "title",
3525
3612
  context: "context"
3526
3613
  },
3527
- prepare(_ref12) {
3614
+ prepare(_ref13) {
3528
3615
  let {
3529
3616
  title,
3530
3617
  context
3531
- } = _ref12;
3618
+ } = _ref13;
3532
3619
  var _a;
3533
3620
  const text = context == null ? void 0 : context.flatMap(block => block == null ? void 0 : block.children).flatMap(child => {
3534
3621
  var _a2;
@@ -3572,7 +3659,13 @@ function randomKey(length) {
3572
3659
  const table = getByteHexTable();
3573
3660
  return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length);
3574
3661
  }
3575
- const PteMods = styled__default.default(ui.Box)(_templateObject12 || (_templateObject12 = _taggedTemplateLiteral(["\n & [data-testid='pt-editor__toolbar-card'] > div > div:last-child {\n display: none;\n }\n & [data-testid='pt-editor'] {\n min-height: 300px;\n }\n & [data-testid='pt-editor'] .pt-inline-object * {\n max-width: 400px;\n }\n"])));
3662
+ var __freeze = Object.freeze;
3663
+ var __defProp = Object.defineProperty;
3664
+ var __template = (cooked, raw) => __freeze(__defProp(cooked, "raw", {
3665
+ value: __freeze(raw || cooked.slice())
3666
+ }));
3667
+ var _a;
3668
+ const PteMods = styled__default.default(ui.Box)(_a || (_a = __template(["\n & [data-testid='pt-editor__toolbar-card'] > div > div:last-child {\n display: none;\n }\n & [data-testid='pt-editor'] {\n min-height: 300px;\n }\n & [data-testid='pt-editor'] .pt-inline-object * {\n max-width: 400px;\n }\n"])));
3576
3669
  function PromptInput(props) {
3577
3670
  useOnlyInlineBlocks(props);
3578
3671
  return /* @__PURE__ */jsxRuntime.jsx(PteMods, {
@@ -3581,9 +3674,9 @@ function PromptInput(props) {
3581
3674
  }
3582
3675
  function useOnlyInlineBlocks(props) {
3583
3676
  react.useEffect(() => {
3584
- var _a;
3677
+ var _a2;
3585
3678
  let needsFix = false;
3586
- const val = ((_a = props.value) != null ? _a : []).map(block => {
3679
+ const val = ((_a2 = props.value) != null ? _a2 : []).map(block => {
3587
3680
  if (block._type === "block") {
3588
3681
  return block;
3589
3682
  }
@@ -3638,7 +3731,7 @@ const fieldReference = sanity.defineType({
3638
3731
  const refs = getFieldRefsWithDocument(schema);
3639
3732
  const fieldRef = refs.find(r => r.key === value);
3640
3733
  if (!fieldRef) {
3641
- return "Field with path \"".concat(value, "\" does not exist in the schema.");
3734
+ return 'Field with path "'.concat(value, '" does not exist in the schema.');
3642
3735
  }
3643
3736
  return true;
3644
3737
  } catch (e) {
@@ -3651,10 +3744,10 @@ const fieldReference = sanity.defineType({
3651
3744
  select: {
3652
3745
  path: "path"
3653
3746
  },
3654
- prepare(_ref13) {
3747
+ prepare(_ref14) {
3655
3748
  let {
3656
3749
  path
3657
- } = _ref13;
3750
+ } = _ref14;
3658
3751
  return {
3659
3752
  title: path,
3660
3753
  path,
@@ -3800,12 +3893,12 @@ const instruction = sanity.defineType({
3800
3893
  title: "title",
3801
3894
  userId: "userId"
3802
3895
  },
3803
- prepare: _ref14 => {
3896
+ prepare: _ref15 => {
3804
3897
  let {
3805
3898
  icon,
3806
3899
  title,
3807
3900
  userId
3808
- } = _ref14;
3901
+ } = _ref15;
3809
3902
  return {
3810
3903
  title,
3811
3904
  icon: icon ? icons.icons[icon] : icons.SparklesIcon,
@@ -4093,6 +4186,100 @@ function PrivateIcon() {
4093
4186
  children: /* @__PURE__ */jsxRuntime.jsx(icons.LockIcon, {})
4094
4187
  });
4095
4188
  }
4189
+ const ImageContext = react.createContext(void 0);
4190
+ function ImageContextProvider(props) {
4191
+ var _a;
4192
+ const {
4193
+ schemaType,
4194
+ path,
4195
+ value
4196
+ } = props;
4197
+ const assetRef = (_a = value == null ? void 0 : value.asset) == null ? void 0 : _a._ref;
4198
+ const [assetRefState, setAssetRefState] = react.useState(assetRef);
4199
+ const {
4200
+ documentId
4201
+ } = useAssistDocumentContext();
4202
+ const {
4203
+ config
4204
+ } = useAiAssistanceConfig();
4205
+ const apiClient = useApiClient(config == null ? void 0 : config.__customApiClient);
4206
+ const {
4207
+ generateCaption
4208
+ } = useGenerateCaption(apiClient);
4209
+ react.useEffect(() => {
4210
+ const captionField = getCaptionFieldOption(schemaType);
4211
+ if (assetRef && documentId && captionField && assetRef !== assetRefState) {
4212
+ setAssetRefState(assetRef);
4213
+ generateCaption({
4214
+ path: sanity.pathToString([...path, captionField]),
4215
+ documentId
4216
+ });
4217
+ }
4218
+ }, [schemaType, path, assetRef, assetRefState, documentId, generateCaption]);
4219
+ const context = react.useMemo(() => {
4220
+ const captionField = getCaptionFieldOption(schemaType);
4221
+ return captionField ? {
4222
+ captionPath: sanity.pathToString([...path, captionField]),
4223
+ assetRef
4224
+ } : void 0;
4225
+ }, [schemaType, path, assetRef]);
4226
+ return /* @__PURE__ */jsxRuntime.jsx(ImageContext.Provider, {
4227
+ value: context,
4228
+ children: props.renderDefault(props)
4229
+ });
4230
+ }
4231
+ function node$1(node2) {
4232
+ return node2;
4233
+ }
4234
+ const generateCaptionsActions = {
4235
+ name: "sanity-assist-generate-captions",
4236
+ useAction(props) {
4237
+ const pathKey = usePathKey(props.path);
4238
+ const {
4239
+ config
4240
+ } = useAiAssistanceConfig();
4241
+ const apiClient = useApiClient(config == null ? void 0 : config.__customApiClient);
4242
+ const {
4243
+ generateCaption,
4244
+ loading
4245
+ } = useGenerateCaption(apiClient);
4246
+ const imageContext = react.useContext(ImageContext);
4247
+ if (imageContext && pathKey === (imageContext == null ? void 0 : imageContext.captionPath)) {
4248
+ const {
4249
+ documentId
4250
+ } = useAssistDocumentContext();
4251
+ return react.useMemo(() => {
4252
+ return node$1({
4253
+ type: "action",
4254
+ icon: loading ? () => /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
4255
+ style: {
4256
+ height: 17
4257
+ },
4258
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {
4259
+ style: {
4260
+ transform: "translateY(6px)"
4261
+ }
4262
+ })
4263
+ }) : icons.ImageIcon,
4264
+ title: "Generate caption",
4265
+ onAction: () => {
4266
+ if (loading) {
4267
+ return;
4268
+ }
4269
+ generateCaption({
4270
+ path: pathKey,
4271
+ documentId: documentId != null ? documentId : ""
4272
+ });
4273
+ },
4274
+ renderAsButton: true,
4275
+ disabled: loading,
4276
+ hidden: !imageContext.assetRef
4277
+ });
4278
+ }, [generateCaption, pathKey, documentId, loading, imageContext]);
4279
+ }
4280
+ return void 0;
4281
+ }
4282
+ };
4096
4283
  function node(node2) {
4097
4284
  return node2;
4098
4285
  }
@@ -4142,6 +4329,7 @@ const assistFieldActions = {
4142
4329
  const isInspectorOpen = (inspector == null ? void 0 : inspector.name) === aiInspectorId;
4143
4330
  const isPathSelected = pathKey === selectedPath;
4144
4331
  const isSelected = isInspectorOpen && isPathSelected;
4332
+ const imageCaptionAction = generateCaptionsActions.useAction(props);
4145
4333
  const manageInstructions = react.useCallback(() => isSelected ? closeInspector(aiInspectorId) : openInspector(aiInspectorId, {
4146
4334
  [fieldPathParam]: pathKey,
4147
4335
  [instructionParam]: void 0
@@ -4171,17 +4359,17 @@ const assistFieldActions = {
4171
4359
  type: "group",
4172
4360
  icon: () => null,
4173
4361
  title: "Run instructions",
4174
- children: instructions.map(instruction => instructionItem({
4362
+ children: [...instructions.map(instruction => instructionItem({
4175
4363
  instruction,
4176
4364
  isPrivate: Boolean(instruction.userId && instruction.userId === (currentUser == null ? void 0 : currentUser.id)),
4177
4365
  onInstructionAction,
4178
4366
  hidden: isHidden,
4179
4367
  documentIsNew: !!documentIsNew,
4180
4368
  assistSupported
4181
- })),
4369
+ })), imageCaptionAction].filter(Boolean),
4182
4370
  expanded: true
4183
4371
  }) : void 0;
4184
- }, [instructions, currentUser == null ? void 0 : currentUser.id, onInstructionAction, isHidden, documentIsNew, assistSupported]);
4372
+ }, [instructions, currentUser == null ? void 0 : currentUser.id, onInstructionAction, isHidden, documentIsNew, assistSupported, imageCaptionAction]);
4185
4373
  const instructionsLength = (instructions == null ? void 0 : instructions.length) || 0;
4186
4374
  const manageInstructionsItem = react.useMemo(() => node({
4187
4375
  type: "action",
@@ -4220,7 +4408,7 @@ const assistFieldActions = {
4220
4408
  title: pluginTitleShort,
4221
4409
  selected: isSelected
4222
4410
  }), [assistSupported, manageInstructions, isSelected]);
4223
- if (instructionsLength === 0) {
4411
+ if (instructionsLength === 0 && !imageCaptionAction) {
4224
4412
  return emptyAction;
4225
4413
  }
4226
4414
  return group;
@@ -4280,13 +4468,13 @@ function useInstructionToaster(documentId, documentSchemaType) {
4280
4468
  return !prevTask && task.ended || !(prevTask == null ? void 0 : prevTask.ended) && task.ended;
4281
4469
  }).filter(task => task.ended && dateFns.isAfter(dateFns.addSeconds(new Date(task.ended), 30), /* @__PURE__ */new Date()));
4282
4470
  endedTasks == null ? void 0 : endedTasks.forEach(task => {
4283
- var _a2;
4284
- const title = getInstructionTitle(task.instruction);
4471
+ var _a2, _b;
4472
+ const title = (_a2 = task.title) != null ? _a2 : getInstructionTitle(task.instruction);
4285
4473
  if (task.reason === "error") {
4286
4474
  toast.push({
4287
4475
  title: "Failed: ".concat(title),
4288
4476
  status: "error",
4289
- description: "Instruction failed. ".concat((_a2 = task.message) != null ? _a2 : ""),
4477
+ description: "Instruction failed. ".concat((_b = task.message) != null ? _b : ""),
4290
4478
  closable: true,
4291
4479
  duration: 1e4
4292
4480
  });
@@ -4333,11 +4521,11 @@ function AssistDocumentInputWrapper(props) {
4333
4521
  documentId
4334
4522
  });
4335
4523
  }
4336
- function AssistDocumentInput(_ref15) {
4524
+ function AssistDocumentInput(_ref16) {
4337
4525
  let {
4338
4526
  documentId,
4339
4527
  ...props
4340
- } = _ref15;
4528
+ } = _ref16;
4341
4529
  useInstructionToaster(documentId, props.schemaType);
4342
4530
  return /* @__PURE__ */jsxRuntime.jsx(FirstAssistedPathProvider, {
4343
4531
  members: props.members,
@@ -4426,12 +4614,12 @@ const assist = sanity.definePlugin(config => {
4426
4614
  unstable_fieldActions: prev => {
4427
4615
  return [...prev, assistFieldActions];
4428
4616
  },
4429
- unstable_languageFilter: (prev, _ref16) => {
4617
+ unstable_languageFilter: (prev, _ref17) => {
4430
4618
  let {
4431
4619
  documentId,
4432
4620
  schema,
4433
4621
  schemaType
4434
- } = _ref16;
4622
+ } = _ref17;
4435
4623
  const docSchema = schema.get(schemaType);
4436
4624
  return [...prev, createAssistDocumentPresence(documentId, docSchema)];
4437
4625
  }
@@ -4462,6 +4650,23 @@ const assist = sanity.definePlugin(config => {
4462
4650
  input: SafeValueInput
4463
4651
  }
4464
4652
  }
4653
+ })(), sanity.definePlugin({
4654
+ name: "".concat(packageName, "/generate-caption"),
4655
+ form: {
4656
+ components: {
4657
+ input: props => {
4658
+ const {
4659
+ schemaType
4660
+ } = props;
4661
+ if (isImage(schemaType)) {
4662
+ return /* @__PURE__ */jsxRuntime.jsx(ImageContextProvider, {
4663
+ ...props
4664
+ });
4665
+ }
4666
+ return props.renderDefault(props);
4667
+ }
4668
+ }
4669
+ }
4465
4670
  })()]
4466
4671
  };
4467
4672
  });