@case-framework/survey-assistant 0.7.0 → 0.8.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.
Files changed (130) hide show
  1. package/README.md +58 -3
  2. package/dist/{attachments-B0hg3vpT.mjs → attachments-BuNni5vB.mjs} +1 -1
  3. package/dist/{attachments-B0hg3vpT.mjs.map → attachments-BuNni5vB.mjs.map} +1 -1
  4. package/dist/{authoring-references-BJQ_1nMX.mjs → authoring-references-DbuOKerg.mjs} +12 -3
  5. package/dist/authoring-references-DbuOKerg.mjs.map +1 -0
  6. package/dist/{capabilities-DVTfogjv.d.mts → capabilities-CmeeAjEc.d.mts} +3 -4
  7. package/dist/capabilities-CmeeAjEc.d.mts.map +1 -0
  8. package/dist/{capabilities-1KNnNO1_.mjs → capabilities-DCMA71PP.mjs} +4 -19
  9. package/dist/capabilities-DCMA71PP.mjs.map +1 -0
  10. package/dist/capabilities-default.d.mts +13 -12
  11. package/dist/capabilities-default.d.mts.map +1 -1
  12. package/dist/capabilities-default.mjs +2 -411
  13. package/dist/{constants-Be91Gay9.d.mts → constants-B6HzpEsx.d.mts} +7 -28
  14. package/dist/constants-B6HzpEsx.d.mts.map +1 -0
  15. package/dist/{constants-0UHGFcRJ.mjs → constants-Ct-vv9cu.mjs} +1 -1
  16. package/dist/{constants-0UHGFcRJ.mjs.map → constants-Ct-vv9cu.mjs.map} +1 -1
  17. package/dist/controller-proxy-D7uQfm5f.d.mts +65 -0
  18. package/dist/controller-proxy-D7uQfm5f.d.mts.map +1 -0
  19. package/dist/{controller-proxy-BH05e-C2.mjs → controller-proxy-DEeFl9IA.mjs} +10 -20
  20. package/dist/controller-proxy-DEeFl9IA.mjs.map +1 -0
  21. package/dist/default-fhSon2RM.mjs +760 -0
  22. package/dist/default-fhSon2RM.mjs.map +1 -0
  23. package/dist/{digest-SJmoYVaK.d.mts → digest-C39WyAWG.d.mts} +2 -3
  24. package/dist/digest-C39WyAWG.d.mts.map +1 -0
  25. package/dist/digest.d.mts +1 -1
  26. package/dist/digest.mjs.map +1 -1
  27. package/dist/{engine-Bo85Oyj0.mjs → engine-nXoCWYpQ.mjs} +755 -590
  28. package/dist/engine-nXoCWYpQ.mjs.map +1 -0
  29. package/dist/engine.d.mts +3 -3
  30. package/dist/engine.mjs +3 -3
  31. package/dist/{fair-guidance-CRYCRxQm.mjs → fair-guidance-BmO4PswW.mjs} +1 -1
  32. package/dist/{fair-guidance-CRYCRxQm.mjs.map → fair-guidance-BmO4PswW.mjs.map} +1 -1
  33. package/dist/{index-Tnqv-yKW.d.mts → index-Ciq7vHIs.d.mts} +80 -141
  34. package/dist/index-Ciq7vHIs.d.mts.map +1 -0
  35. package/dist/{index-nhrgbgO5.d.mts → index-D7wT6P3t.d.mts} +277 -60
  36. package/dist/index-D7wT6P3t.d.mts.map +1 -0
  37. package/dist/{index-l_EK4yK7.d.mts → index-WB5kfnz0.d.mts} +15 -71
  38. package/dist/index-WB5kfnz0.d.mts.map +1 -0
  39. package/dist/{index-x0qprHgK.d.mts → index-r5riv4md.d.mts} +33 -24
  40. package/dist/index-r5riv4md.d.mts.map +1 -0
  41. package/dist/{lifecycle-Bx0aq_4S.d.mts → lifecycle-Dm8u7QFh.d.mts} +34 -18
  42. package/dist/lifecycle-Dm8u7QFh.d.mts.map +1 -0
  43. package/dist/{memory-thread-repository-KWHQWFEW.mjs → memory-thread-repository-DAnOGIB3.mjs} +51 -27
  44. package/dist/memory-thread-repository-DAnOGIB3.mjs.map +1 -0
  45. package/dist/{protocol-BhzQbx81.mjs → protocol-CF4Bh_Ch.mjs} +118 -36
  46. package/dist/protocol-CF4Bh_Ch.mjs.map +1 -0
  47. package/dist/protocol.d.mts +4 -4
  48. package/dist/protocol.mjs +3 -3
  49. package/dist/{react-B3ybjJ-X.mjs → react-C_GY-Fsc.mjs} +146 -39
  50. package/dist/react-C_GY-Fsc.mjs.map +1 -0
  51. package/dist/react-integration.d.mts +2 -2
  52. package/dist/react-integration.mjs +2 -2
  53. package/dist/react.d.mts +3 -3
  54. package/dist/react.mjs +3 -3
  55. package/dist/references/assistant-operations.md +100 -31
  56. package/dist/references/core-rules.md +6 -3
  57. package/dist/references/embedded-forms.md +34 -14
  58. package/dist/references/expressions.md +220 -58
  59. package/dist/references/fair-by-design.md +9 -9
  60. package/dist/references/item-types.md +305 -71
  61. package/dist/references/response-variables.md +38 -0
  62. package/dist/references/source-material-surveys.md +4 -3
  63. package/dist/references/survey-data-model.md +23 -8
  64. package/dist/{request-context-CG4SWijt.mjs → request-context-Dg4jSwN1.mjs} +4 -10
  65. package/dist/request-context-Dg4jSwN1.mjs.map +1 -0
  66. package/dist/{request-guardrails-TmgQtqp4.mjs → request-guardrails-C0ugBOp0.mjs} +6 -5
  67. package/dist/request-guardrails-C0ugBOp0.mjs.map +1 -0
  68. package/dist/server-agent.d.mts +37 -39
  69. package/dist/server-agent.d.mts.map +1 -1
  70. package/dist/server-agent.mjs +45 -20
  71. package/dist/server-agent.mjs.map +1 -1
  72. package/dist/server-runtime.d.mts +23 -42
  73. package/dist/server-runtime.d.mts.map +1 -1
  74. package/dist/server-runtime.mjs +12 -12
  75. package/dist/server-runtime.mjs.map +1 -1
  76. package/dist/server-tasks.d.mts +2 -2
  77. package/dist/server-tasks.mjs +2 -313
  78. package/dist/server-tools.d.mts +1 -1
  79. package/dist/server-tools.mjs +1 -1
  80. package/dist/server.d.mts +13 -36
  81. package/dist/server.d.mts.map +1 -1
  82. package/dist/server.mjs +5 -5
  83. package/dist/server.mjs.map +1 -1
  84. package/dist/storage-postgres.d.mts +9 -25
  85. package/dist/storage-postgres.d.mts.map +1 -1
  86. package/dist/storage-postgres.mjs +5 -4
  87. package/dist/storage-postgres.mjs.map +1 -1
  88. package/dist/{tasks-CYqrcaRO.d.mts → tasks-B9h3LPam.d.mts} +18 -34
  89. package/dist/tasks-B9h3LPam.d.mts.map +1 -0
  90. package/dist/tasks-BZEiwgxA.mjs +396 -0
  91. package/dist/tasks-BZEiwgxA.mjs.map +1 -0
  92. package/dist/thread-documents-DrHbaXqP.d.mts +119 -0
  93. package/dist/thread-documents-DrHbaXqP.d.mts.map +1 -0
  94. package/dist/{thread-handlers-DBAaU7BA.d.mts → thread-handlers-Bef0td9N.d.mts} +8 -40
  95. package/dist/thread-handlers-Bef0td9N.d.mts.map +1 -0
  96. package/dist/{tools-BvSovehT.mjs → tools-CEsv-WoO.mjs} +296 -105
  97. package/dist/tools-CEsv-WoO.mjs.map +1 -0
  98. package/dist/ui.css +1 -1
  99. package/dist/ui.d.mts +15 -54
  100. package/dist/ui.d.mts.map +1 -1
  101. package/dist/ui.mjs +172 -137
  102. package/dist/ui.mjs.map +1 -1
  103. package/docs/integration.md +11 -1
  104. package/package.json +40 -35
  105. package/dist/authoring-references-BJQ_1nMX.mjs.map +0 -1
  106. package/dist/capabilities-1KNnNO1_.mjs.map +0 -1
  107. package/dist/capabilities-DVTfogjv.d.mts.map +0 -1
  108. package/dist/capabilities-default.mjs.map +0 -1
  109. package/dist/constants-Be91Gay9.d.mts.map +0 -1
  110. package/dist/controller-proxy-BH05e-C2.mjs.map +0 -1
  111. package/dist/controller-proxy-Bd0ZHBPF.d.mts +0 -85
  112. package/dist/controller-proxy-Bd0ZHBPF.d.mts.map +0 -1
  113. package/dist/digest-SJmoYVaK.d.mts.map +0 -1
  114. package/dist/engine-Bo85Oyj0.mjs.map +0 -1
  115. package/dist/index-Tnqv-yKW.d.mts.map +0 -1
  116. package/dist/index-l_EK4yK7.d.mts.map +0 -1
  117. package/dist/index-nhrgbgO5.d.mts.map +0 -1
  118. package/dist/index-x0qprHgK.d.mts.map +0 -1
  119. package/dist/lifecycle-Bx0aq_4S.d.mts.map +0 -1
  120. package/dist/memory-thread-repository-KWHQWFEW.mjs.map +0 -1
  121. package/dist/protocol-BhzQbx81.mjs.map +0 -1
  122. package/dist/react-B3ybjJ-X.mjs.map +0 -1
  123. package/dist/request-context-CG4SWijt.mjs.map +0 -1
  124. package/dist/request-guardrails-TmgQtqp4.mjs.map +0 -1
  125. package/dist/server-tasks.mjs.map +0 -1
  126. package/dist/tasks-CYqrcaRO.d.mts.map +0 -1
  127. package/dist/thread-documents-rmd6nyX9.d.mts +0 -107
  128. package/dist/thread-documents-rmd6nyX9.d.mts.map +0 -1
  129. package/dist/thread-handlers-DBAaU7BA.d.mts.map +0 -1
  130. package/dist/tools-BvSovehT.mjs.map +0 -1
@@ -1,9 +1,9 @@
1
- import { H as surveyDocumentVersionSchema, Lt as getSurveyAssistantEmbeddedBinaryMarker, M as surveyAssistantThreadSchema, Mt as parseSurveyAssistantError, N as surveyAssistantThreadTranscriptSchema, Rt as isSurveyAssistantSensitiveMetadataKey, f as surveyChangeSetSchema, j as surveyAssistantThreadListSchema, l as surveyAssistantTurnFinalSchema, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE, o as surveyAssistantApplyOutcomeSchema, p as surveyAssistantModelCatalogSchema, r as applyReceiptSchema, zt as redactSurveyAssistantDiagnosticSecrets } from "./protocol-BhzQbx81.mjs";
1
+ import { F as surveyAssistantThreadTranscriptSchema, Ht as isSurveyAssistantSensitiveMetadataKey, It as parseSurveyAssistantError, N as surveyAssistantThreadListSchema, P as surveyAssistantThreadSchema, Ut as redactSurveyAssistantDiagnosticSecrets, Vt as getSurveyAssistantEmbeddedBinaryMarker, W as surveyDocumentVersionSchema, f as surveyChangeSetSchema, l as surveyAssistantTurnFinalSchema, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE, o as surveyAssistantApplyOutcomeSchema, p as surveyAssistantModelCatalogSchema, r as applyReceiptSchema } from "./protocol-CF4Bh_Ch.mjs";
2
2
  import { hashString } from "./digest.mjs";
3
- import { a as applySurveyAssistantLaunchUIContext, l as readSurveyAssistantJson } from "./controller-proxy-BH05e-C2.mjs";
3
+ import { c as readSurveyAssistantJson, i as applySurveyAssistantLaunchUIContext } from "./controller-proxy-DEeFl9IA.mjs";
4
4
  import { DefaultChatTransport } from "ai";
5
5
  import { Zip, ZipPassThrough } from "fflate";
6
- import { useCallback, useEffect, useEffectEvent, useMemo, useReducer, useRef, useState } from "react";
6
+ import { useCallback, useEffect, useEffectEvent, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
7
7
  import { useChat } from "@ai-sdk/react";
8
8
  //#region src/react/session-state.ts
9
9
  const isSurveyAssistantTurnActive = ({ isStreaming, state }) => state !== "aborted" && (isStreaming || state === "submitting" || state === "streaming" || state === "applying");
@@ -193,10 +193,6 @@ const createSurveyAssistantThreadClient = (api = "/api/survey-assistant/threads"
193
193
  }));
194
194
  return surveyAssistantThreadSchema.parse(body.thread);
195
195
  },
196
- async list() {
197
- const body = await readSurveyAssistantJson(await fetch(api, { cache: "no-store" }));
198
- return surveyAssistantThreadListSchema.parse(body).threads;
199
- },
200
196
  async listPage(options) {
201
197
  const search = new URLSearchParams();
202
198
  if (options?.cursor) search.set("cursor", options.cursor);
@@ -236,7 +232,7 @@ const createSurveyAssistantThreadClient = (api = "/api/survey-assistant/threads"
236
232
  });
237
233
  //#endregion
238
234
  //#region src/react/support-bundle-limits.ts
239
- const MEBIBYTE = 1024 * 1024;
235
+ const MEBIBYTE = 1048576;
240
236
  const SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_LIMITS = {
241
237
  attemptEvents: 200,
242
238
  attemptStoreBytes: 48 * MEBIBYTE,
@@ -505,7 +501,7 @@ const createSurveyAssistantDiagnosticStore = (overrides) => {
505
501
  };
506
502
  //#endregion
507
503
  //#region package.json
508
- var version = "0.7.0";
504
+ var version = "0.8.0";
509
505
  //#endregion
510
506
  //#region src/react/support-bundle.ts
511
507
  const SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_SELECTION = {
@@ -764,8 +760,9 @@ const prepareSurveyAssistantSupportBundle = async ({ config, controller, diagnos
764
760
  const filenames = disambiguateFilenames(availableAttachments.map(({ reference }) => reference));
765
761
  for (const [index, { reference, stored }] of availableAttachments.entries()) {
766
762
  abortIfNeeded(signal);
763
+ const bytes = dataUrlToBytes(stored.dataUrl);
767
764
  pushPreparedEntry(entries, unavailable, {
768
- bytes: dataUrlToBytes(stored.dataUrl),
765
+ bytes,
769
766
  category: "attachments",
770
767
  path: `attachments/${filenames[index]}`,
771
768
  source: "browser-session"
@@ -924,10 +921,11 @@ const createRequiredEntries = (prepared, selection, config, generatedAt) => {
924
921
  const estimateArchiveBytes = (entries) => entries.reduce((total, entry) => total + entry.bytes.byteLength + encoder.encode(entry.path).byteLength * 2 + 110, 22);
925
922
  const estimateSurveyAssistantSupportBundleBytes = (prepared, selection, config) => {
926
923
  if (!isSurveyAssistantSupportBundleEnabled(config)) return 0;
927
- return estimateArchiveBytes([...createRequiredEntries(prepared, selection, config, (/* @__PURE__ */ new Date()).toISOString()), ...prepared.entries.filter((entry) => selection[entry.category]).map(({ bytes, path }) => ({
924
+ const entries = [...createRequiredEntries(prepared, selection, config, (/* @__PURE__ */ new Date()).toISOString()), ...prepared.entries.filter((entry) => selection[entry.category]).map(({ bytes, path }) => ({
928
925
  bytes,
929
926
  path
930
- }))]);
927
+ }))];
928
+ return estimateArchiveBytes(entries);
931
929
  };
932
930
  const generateSurveyAssistantSupportBundle = async (prepared, selection, config) => {
933
931
  assertSurveyAssistantSupportBundleEnabled(config);
@@ -1154,30 +1152,85 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1154
1152
  const [authorizationError, setAuthorizationError] = useState(null);
1155
1153
  const handledTurnIdsRef = useRef(/* @__PURE__ */ new Set());
1156
1154
  const localTurnAwaitingApplyRef = useRef(false);
1155
+ const turnOwnedRef = useRef(false);
1156
+ const turnGenerationRef = useRef(0);
1157
+ const mountedRef = useRef(false);
1157
1158
  const localTurnStreamStartedRef = useRef(false);
1158
1159
  const captureSettledVersionRef = useRef(false);
1159
1160
  const lastSubmittedUIContextRef = useRef(void 0);
1160
1161
  const lastSubmittedModelIdRef = useRef(void 0);
1161
1162
  const previousApplyOutcomesRef = useRef(/* @__PURE__ */ new Map());
1162
1163
  const capturedChatErrorRef = useRef(void 0);
1164
+ const submittedDocumentSessionIdRef = useRef(void 0);
1165
+ const previousAssistantMessageRef = useRef(void 0);
1166
+ const controllerRef = useRef(controller);
1167
+ const invalidateTurn = useCallback(() => {
1168
+ turnGenerationRef.current += 1;
1169
+ turnOwnedRef.current = false;
1170
+ localTurnAwaitingApplyRef.current = false;
1171
+ localTurnStreamStartedRef.current = false;
1172
+ captureSettledVersionRef.current = false;
1173
+ }, []);
1174
+ const sessionScope = JSON.stringify([
1175
+ api,
1176
+ resourceId,
1177
+ surveyId,
1178
+ threadId
1179
+ ]);
1180
+ const previousSessionScopeRef = useRef(sessionScope);
1181
+ useLayoutEffect(() => {
1182
+ mountedRef.current = true;
1183
+ if (previousSessionScopeRef.current !== sessionScope) {
1184
+ previousSessionScopeRef.current = sessionScope;
1185
+ dispatch({
1186
+ type: "reset",
1187
+ hasTranscript: initialMessages.length > 0
1188
+ });
1189
+ setApplyResultsByChangeId({});
1190
+ setAuthorizationError(null);
1191
+ handledTurnIdsRef.current.clear();
1192
+ previousApplyOutcomesRef.current.clear();
1193
+ lastSubmittedUIContextRef.current = void 0;
1194
+ lastSubmittedModelIdRef.current = void 0;
1195
+ submittedDocumentSessionIdRef.current = void 0;
1196
+ previousAssistantMessageRef.current = void 0;
1197
+ capturedChatErrorRef.current = void 0;
1198
+ }
1199
+ return () => {
1200
+ mountedRef.current = false;
1201
+ invalidateTurn();
1202
+ };
1203
+ }, [sessionScope, invalidateTurn]);
1204
+ useLayoutEffect(() => {
1205
+ controllerRef.current = controller;
1206
+ if (!turnOwnedRef.current) return;
1207
+ try {
1208
+ if (controller?.getSnapshot()?.version.sessionId === submittedDocumentSessionIdRef.current) return;
1209
+ } catch {}
1210
+ invalidateTurn();
1211
+ dispatch({ type: "aborted" });
1212
+ }, [controller, invalidateTurn]);
1213
+ const transport = useMemo(() => createSurveyAssistantTransport({
1214
+ api,
1215
+ resourceId,
1216
+ surveyId,
1217
+ threadId
1218
+ }), [
1219
+ api,
1220
+ resourceId,
1221
+ surveyId,
1222
+ threadId
1223
+ ]);
1163
1224
  const { messages, setMessages, sendMessage, status, stop: stopChat, error, clearError, regenerate } = useChat({
1164
1225
  id: threadId,
1165
1226
  messages: initialMessages,
1166
- transport: useMemo(() => createSurveyAssistantTransport({
1167
- api,
1168
- resourceId,
1169
- surveyId,
1170
- threadId
1171
- }), [
1172
- api,
1173
- resourceId,
1174
- surveyId,
1175
- threadId
1176
- ])
1227
+ transport
1177
1228
  });
1178
1229
  const isStreaming = status === "submitted" || status === "streaming";
1179
1230
  const messagesRef = useRef(messages);
1180
- messagesRef.current = messages;
1231
+ useLayoutEffect(() => {
1232
+ messagesRef.current = messages;
1233
+ }, [messages]);
1181
1234
  const isTurnActive = isSurveyAssistantTurnActive({
1182
1235
  isStreaming,
1183
1236
  state
@@ -1205,7 +1258,9 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1205
1258
  retryable: false
1206
1259
  });
1207
1260
  } catch {}
1261
+ const generation = turnGenerationRef.current;
1208
1262
  queueMicrotask(() => {
1263
+ if (!mountedRef.current || turnGenerationRef.current !== generation) return;
1209
1264
  setAuthorizationError(message);
1210
1265
  dispatch({ type: "failed" });
1211
1266
  });
@@ -1231,11 +1286,13 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1231
1286
  };
1232
1287
  }, [isTurnActive]);
1233
1288
  useEffect(() => {
1234
- if (!captureSettledVersionRef.current || isStreaming || state !== "completed" && state !== "failed" && state !== "aborted" && state !== "applied") return;
1289
+ if (isStreaming || state !== "completed" && state !== "failed" && state !== "aborted" && state !== "applied") return;
1290
+ turnOwnedRef.current = false;
1291
+ if (!captureSettledVersionRef.current) return;
1235
1292
  captureSettledVersionRef.current = false;
1236
1293
  try {
1237
1294
  const snapshot = controller?.getSnapshot();
1238
- if (snapshot) writeSettledDocumentVersion({
1295
+ if (snapshot && snapshot.version.sessionId === submittedDocumentSessionIdRef.current) writeSettledDocumentVersion({
1239
1296
  resourceId,
1240
1297
  snapshot,
1241
1298
  threadId
@@ -1254,6 +1311,8 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1254
1311
  return;
1255
1312
  }
1256
1313
  if (!localTurnAwaitingApplyRef.current) return;
1314
+ if (!localTurnStreamStartedRef.current && [...messages].reverse().find((message) => message.role === "assistant") === previousAssistantMessageRef.current) return;
1315
+ if ("turnFinal" in turnAuthorization && handledTurnIdsRef.current.has(turnAuthorization.turnFinal.turnId)) return;
1257
1316
  if (turnAuthorization.status === "pending") {
1258
1317
  if (!localTurnStreamStartedRef.current) return;
1259
1318
  const timeoutId = window.setTimeout(() => {
@@ -1317,6 +1376,9 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1317
1376
  dispatch({ type: "completed" });
1318
1377
  return;
1319
1378
  }
1379
+ captureSettledVersionRef.current = false;
1380
+ const generation = turnGenerationRef.current;
1381
+ const isCurrentTurn = () => mountedRef.current && turnGenerationRef.current === generation;
1320
1382
  dispatch({ type: "apply-started" });
1321
1383
  (async () => {
1322
1384
  if (applyPolicy === "review") {
@@ -1328,6 +1390,7 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1328
1390
  turnFinal
1329
1391
  });
1330
1392
  } catch (error) {
1393
+ if (!isCurrentTurn()) return;
1331
1394
  const message = error instanceof Error && error.message === "No survey assistant review adapter is available." ? error.message : "The survey assistant review could not be completed.";
1332
1395
  rememberApplyOutcome(createApplyOutcome({
1333
1396
  turnId: turnFinal.turnId,
@@ -1338,6 +1401,7 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1338
1401
  reportAuthorizationError(message);
1339
1402
  return;
1340
1403
  }
1404
+ if (!isCurrentTurn()) return;
1341
1405
  if (!approved) {
1342
1406
  rememberApplyOutcome(createApplyOutcome({
1343
1407
  turnId: turnFinal.turnId,
@@ -1349,7 +1413,9 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1349
1413
  return;
1350
1414
  }
1351
1415
  }
1352
- if (!controller?.applyAssistantChanges) {
1416
+ if (!isCurrentTurn()) return;
1417
+ const currentController = controllerRef.current;
1418
+ if (!currentController?.applyAssistantChanges) {
1353
1419
  const message = "No survey editor apply adapter is available.";
1354
1420
  rememberApplyOutcome(createApplyOutcome({
1355
1421
  turnId: turnFinal.turnId,
@@ -1369,20 +1435,31 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1369
1435
  const allChangesApplied = () => hasCompleteApplyResults() && results.every((result) => result.status === "applied");
1370
1436
  const retainApplyResults = () => {
1371
1437
  const entries = results.map((result) => [result.changeId, result]);
1372
- queueMicrotask(() => setApplyResultsByChangeId((current) => ({
1373
- ...current,
1374
- ...Object.fromEntries(entries)
1375
- })));
1438
+ queueMicrotask(() => {
1439
+ if (!isCurrentTurn()) return;
1440
+ setApplyResultsByChangeId((current) => ({
1441
+ ...current,
1442
+ ...Object.fromEntries(entries)
1443
+ }));
1444
+ });
1376
1445
  };
1377
1446
  try {
1378
- const beforeSnapshot = controller.getSnapshot();
1447
+ const beforeSnapshot = currentController.getSnapshot();
1448
+ if (!isCurrentTurn()) return;
1379
1449
  if (!beforeSnapshot) throw new Error("Editor snapshot unavailable.");
1450
+ if (beforeSnapshot.version.sessionId !== submittedDocumentSessionIdRef.current) {
1451
+ invalidateTurn();
1452
+ dispatch({ type: "aborted" });
1453
+ return;
1454
+ }
1455
+ if (!isCurrentTurn()) return;
1380
1456
  applyStarted = true;
1381
- results.push(...controller.applyAssistantChanges(turnAuthorization.changeSets).results);
1457
+ results.push(...currentController.applyAssistantChanges(turnAuthorization.changeSets).results);
1458
+ if (!isCurrentTurn()) return;
1382
1459
  retainApplyResults();
1383
1460
  const receipts = createApplyReceipts({
1384
1461
  beforeSnapshot,
1385
- afterSnapshot: controller.getSnapshot(),
1462
+ afterSnapshot: currentController.getSnapshot(),
1386
1463
  changeSets: turnAuthorization.changeSets,
1387
1464
  results,
1388
1465
  turnFinal
@@ -1390,7 +1467,9 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1390
1467
  try {
1391
1468
  diagnosticStore?.recordApplyReceipts(threadId, receipts);
1392
1469
  } catch {}
1470
+ if (!isCurrentTurn()) return;
1393
1471
  onApplyReceipts?.(receipts);
1472
+ if (!isCurrentTurn()) return;
1394
1473
  if (!hasCompleteApplyResults()) throw new Error("The host returned mismatched apply results.");
1395
1474
  if (!allChangesApplied()) {
1396
1475
  rememberApplyOutcome(createApplyOutcome({
@@ -1408,9 +1487,24 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1408
1487
  receipts,
1409
1488
  turnFinal
1410
1489
  });
1490
+ if (!isCurrentTurn()) return;
1491
+ const settledSnapshot = controllerRef.current?.getSnapshot();
1492
+ if (!isCurrentTurn()) return;
1493
+ if (!settledSnapshot) throw new Error("Editor snapshot unavailable after settlement.");
1494
+ if (settledSnapshot.version.sessionId !== submittedDocumentSessionIdRef.current) {
1495
+ invalidateTurn();
1496
+ dispatch({ type: "aborted" });
1497
+ return;
1498
+ }
1499
+ writeSettledDocumentVersion({
1500
+ resourceId,
1501
+ snapshot: settledSnapshot,
1502
+ threadId
1503
+ });
1411
1504
  previousApplyOutcomesRef.current.delete(applyOutcomeScopeKey);
1412
1505
  dispatch({ type: "applied" });
1413
1506
  } catch {
1507
+ if (!isCurrentTurn()) return;
1414
1508
  retainApplyResults();
1415
1509
  const applied = allChangesApplied();
1416
1510
  const message = applied ? "The assistant changes were applied locally but could not be settled by the host." : applyStarted ? "The host could not complete the assistant apply lifecycle. Some changes may already have been applied." : "The editor state was unavailable before applying the assistant changes. No changes were applied.";
@@ -1430,11 +1524,13 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1430
1524
  controller,
1431
1525
  diagnosticStore,
1432
1526
  isStreaming,
1527
+ invalidateTurn,
1433
1528
  onApplyReceipts,
1434
1529
  onReviewChangeSets,
1435
1530
  onSettleApply,
1436
1531
  reportAuthorizationError,
1437
1532
  rememberApplyOutcome,
1533
+ resourceId,
1438
1534
  messages,
1439
1535
  threadId,
1440
1536
  turnAuthorization
@@ -1463,7 +1559,7 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1463
1559
  const submit = useCallback(({ files, modelId: submittedModelId, text: rawText, uiContext }) => {
1464
1560
  const text = rawText.trim();
1465
1561
  if (!text && files.length === 0) return false;
1466
- if (isStreaming || localTurnAwaitingApplyRef.current) return false;
1562
+ if (!mountedRef.current || isStreaming || turnOwnedRef.current) return false;
1467
1563
  let snapshot;
1468
1564
  try {
1469
1565
  snapshot = applySurveyAssistantLaunchUIContext(controller?.getSnapshot() ?? null, uiContext);
@@ -1471,6 +1567,10 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1471
1567
  reportAuthorizationError("The editor state was unavailable before sending the assistant request. No request was sent.");
1472
1568
  return false;
1473
1569
  }
1570
+ turnOwnedRef.current = true;
1571
+ submittedDocumentSessionIdRef.current = snapshot?.version.sessionId;
1572
+ previousAssistantMessageRef.current = [...messagesRef.current].reverse().find((message) => message.role === "assistant");
1573
+ turnGenerationRef.current += 1;
1474
1574
  localTurnAwaitingApplyRef.current = true;
1475
1575
  localTurnStreamStartedRef.current = false;
1476
1576
  setAuthorizationError(null);
@@ -1522,12 +1622,12 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1522
1622
  threadId
1523
1623
  ]);
1524
1624
  const stop = useCallback(() => {
1525
- localTurnAwaitingApplyRef.current = false;
1526
- localTurnStreamStartedRef.current = false;
1625
+ invalidateTurn();
1527
1626
  dispatch({ type: "aborted" });
1528
1627
  stopChat();
1529
- }, [stopChat]);
1628
+ }, [invalidateTurn, stopChat]);
1530
1629
  const retry = useCallback(() => {
1630
+ if (!mountedRef.current || isStreaming || turnOwnedRef.current) return;
1531
1631
  let snapshot;
1532
1632
  try {
1533
1633
  snapshot = applySurveyAssistantLaunchUIContext(controller?.getSnapshot() ?? null, lastSubmittedUIContextRef.current);
@@ -1535,6 +1635,10 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1535
1635
  reportAuthorizationError("The editor state was unavailable before retrying the assistant request. No request was sent.");
1536
1636
  return;
1537
1637
  }
1638
+ turnOwnedRef.current = true;
1639
+ submittedDocumentSessionIdRef.current = snapshot?.version.sessionId;
1640
+ previousAssistantMessageRef.current = [...messagesRef.current].reverse().find((message) => message.role === "assistant");
1641
+ turnGenerationRef.current += 1;
1538
1642
  localTurnAwaitingApplyRef.current = true;
1539
1643
  localTurnStreamStartedRef.current = false;
1540
1644
  setAuthorizationError(null);
@@ -1573,6 +1677,7 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1573
1677
  controller,
1574
1678
  diagnosticStore,
1575
1679
  modelId,
1680
+ isStreaming,
1576
1681
  regenerate,
1577
1682
  resourceId,
1578
1683
  reportAuthorizationError,
@@ -1582,6 +1687,7 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1582
1687
  applyResultsByChangeId,
1583
1688
  authorizationError,
1584
1689
  dismissError: useCallback(() => {
1690
+ if (turnOwnedRef.current || isStreaming) return;
1585
1691
  localTurnAwaitingApplyRef.current = false;
1586
1692
  localTurnStreamStartedRef.current = false;
1587
1693
  if (!hasUsefulLatestAssistantResponse) setMessages(pruneFailedMessagesForDisplay);
@@ -1599,6 +1705,7 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1599
1705
  diagnosticStore,
1600
1706
  hasUsefulLatestAssistantResponse,
1601
1707
  messages.length,
1708
+ isStreaming,
1602
1709
  setMessages,
1603
1710
  threadId
1604
1711
  ]),
@@ -1617,4 +1724,4 @@ const useSurveyAssistantSession = ({ api, applyPolicy, controller, diagnosticSto
1617
1724
  //#endregion
1618
1725
  export { resolveLatestSurveyTurnAuthorization as C, reduceSurveyAssistantSessionState as D, isSurveyAssistantTurnActive as E, parseSurveyChangeSet as S, unwrapSurveyAssistantToolOutput as T, createSurveyAssistantThreadClient as _, createSurveyAssistantSupportDetails as a, createApplyReceipts as b, estimateSurveyAssistantSupportBundleBytes as c, prepareSurveyAssistantSupportBundle as d, sanitizeSurveyAssistantSupportValue as f, resolveSurveyAssistantSupportBundleLimits as g, SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_LIMITS as h, SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_SELECTION as i, generateSurveyAssistantSupportBundle as l, createSurveyAssistantDiagnosticStore as m, createSurveyAssistantModelCatalogClient as n, createSurveyAssistantSupportMailto as o, createSurveyAssistantDiagnosticId as p, useSurveyAssistantModelCatalog as r, downloadSurveyAssistantSupportBundle as s, useSurveyAssistantSession as t, isSurveyAssistantSupportBundleEnabled as u, createSurveyAssistantTransport as v, resolveSurveyTurnOutcome as w, getSurveyDocumentVersionFromSnapshot as x, collectSurveyChangeSets as y };
1619
1726
 
1620
- //# sourceMappingURL=react-B3ybjJ-X.mjs.map
1727
+ //# sourceMappingURL=react-C_GY-Fsc.mjs.map