@case-framework/survey-assistant 0.2.1 → 0.2.3

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 (102) hide show
  1. package/dist/{authoring-references-DYuOAdVx.mjs → authoring-references-ChDTVnms.mjs} +8 -2
  2. package/dist/authoring-references-ChDTVnms.mjs.map +1 -0
  3. package/dist/{capabilities-DlC1l6qy.d.mts → capabilities-CnsVuJ1k.d.mts} +12 -4
  4. package/dist/capabilities-CnsVuJ1k.d.mts.map +1 -0
  5. package/dist/capabilities-default.d.mts +1 -1
  6. package/dist/capabilities-default.d.mts.map +1 -1
  7. package/dist/capabilities-default.mjs +38 -4
  8. package/dist/capabilities-default.mjs.map +1 -1
  9. package/dist/{constants-CgV4cTg5.d.mts → constants-BK1-g6pR.d.mts} +12 -7
  10. package/dist/constants-BK1-g6pR.d.mts.map +1 -0
  11. package/dist/{controller-proxy-BzpEOygv.d.mts → controller-proxy-CIDRd8Wu.d.mts} +2 -2
  12. package/dist/{controller-proxy-BzpEOygv.d.mts.map → controller-proxy-CIDRd8Wu.d.mts.map} +1 -1
  13. package/dist/{controller-proxy-0WJZUZYx.mjs → controller-proxy-DY36XFV3.mjs} +2 -2
  14. package/dist/{controller-proxy-0WJZUZYx.mjs.map → controller-proxy-DY36XFV3.mjs.map} +1 -1
  15. package/dist/{digest-BvXpeWcR.d.mts → digest-Dyjch_sC.d.mts} +2 -2
  16. package/dist/{digest-BvXpeWcR.d.mts.map → digest-Dyjch_sC.d.mts.map} +1 -1
  17. package/dist/digest.d.mts +1 -1
  18. package/dist/{engine-0AJrv0hI.mjs → engine-CWTuN3o2.mjs} +866 -663
  19. package/dist/engine-CWTuN3o2.mjs.map +1 -0
  20. package/dist/engine.d.mts +3 -3
  21. package/dist/engine.mjs +3 -3
  22. package/dist/fair-guidance-CEdJYccK.mjs +21 -0
  23. package/dist/fair-guidance-CEdJYccK.mjs.map +1 -0
  24. package/dist/form-authoring-DCd9XfXf.mjs +155 -0
  25. package/dist/form-authoring-DCd9XfXf.mjs.map +1 -0
  26. package/dist/{index-BUF-sE8j.d.mts → index-Bp5W_oPa.d.mts} +27 -7
  27. package/dist/index-Bp5W_oPa.d.mts.map +1 -0
  28. package/dist/{index-BdXb6jER.d.mts → index-CPOQgkTN.d.mts} +67 -6
  29. package/dist/index-CPOQgkTN.d.mts.map +1 -0
  30. package/dist/{index-BiTT71Xp.d.mts → index-EDL1V168.d.mts} +101 -7
  31. package/dist/{index-BiTT71Xp.d.mts.map → index-EDL1V168.d.mts.map} +1 -1
  32. package/dist/{index-BNdvGEaq.d.mts → index-SPHf3OoJ.d.mts} +9 -3
  33. package/dist/index-SPHf3OoJ.d.mts.map +1 -0
  34. package/dist/{memory-thread-repository-1ocPOda8.mjs → memory-thread-repository-acbz6HZJ.mjs} +181 -26
  35. package/dist/memory-thread-repository-acbz6HZJ.mjs.map +1 -0
  36. package/dist/{protocol-DpCYmCjr.mjs → protocol-DATvkr1S.mjs} +125 -6
  37. package/dist/protocol-DATvkr1S.mjs.map +1 -0
  38. package/dist/protocol.d.mts +3 -3
  39. package/dist/protocol.mjs +2 -2
  40. package/dist/{react-DXK5zWNo.mjs → react-3kSE6WtS.mjs} +127 -9
  41. package/dist/react-3kSE6WtS.mjs.map +1 -0
  42. package/dist/react-integration.d.mts +1 -1
  43. package/dist/react-integration.mjs +1 -1
  44. package/dist/react.d.mts +2 -2
  45. package/dist/react.mjs +2 -2
  46. package/dist/references/assistant-operations.md +13 -18
  47. package/dist/references/embedded-forms.md +41 -2
  48. package/dist/references/expressions.md +17 -9
  49. package/dist/references/fair-by-design.md +80 -0
  50. package/dist/references/item-types.md +19 -3
  51. package/dist/references/localization.md +7 -4
  52. package/dist/references/source-material-surveys.md +6 -4
  53. package/dist/{request-context-BBzU3VdG.mjs → request-context-BEjnaaFr.mjs} +10 -5
  54. package/dist/request-context-BEjnaaFr.mjs.map +1 -0
  55. package/dist/server-agent.d.mts +28 -8
  56. package/dist/server-agent.d.mts.map +1 -1
  57. package/dist/server-agent.mjs +70 -13
  58. package/dist/server-agent.mjs.map +1 -1
  59. package/dist/server-runtime.d.mts +22 -11
  60. package/dist/server-runtime.d.mts.map +1 -1
  61. package/dist/server-runtime.mjs +47 -19
  62. package/dist/server-runtime.mjs.map +1 -1
  63. package/dist/server-tasks.d.mts +1 -1
  64. package/dist/server-tasks.mjs +4 -3
  65. package/dist/server-tasks.mjs.map +1 -1
  66. package/dist/server-tools.d.mts +1 -1
  67. package/dist/server-tools.mjs +1 -1
  68. package/dist/server.d.mts +16 -7
  69. package/dist/server.d.mts.map +1 -1
  70. package/dist/server.mjs +4 -4
  71. package/dist/storage-postgres.d.mts +1 -1
  72. package/dist/{tasks-BuLnWrR4.d.mts → tasks-DIZgr4nD.d.mts} +8 -4
  73. package/dist/tasks-DIZgr4nD.d.mts.map +1 -0
  74. package/dist/{thread-documents-BlxNjc7S.d.mts → thread-documents-C3kf0Vds.d.mts} +1 -1
  75. package/dist/{thread-documents-BlxNjc7S.d.mts.map → thread-documents-C3kf0Vds.d.mts.map} +1 -1
  76. package/dist/{thread-handlers-6L8sAreR.d.mts → thread-handlers-DZ1WsorO.d.mts} +9 -4
  77. package/dist/thread-handlers-DZ1WsorO.d.mts.map +1 -0
  78. package/dist/{tools-wgLen05n.mjs → tools-GDd5_GUh.mjs} +403 -77
  79. package/dist/tools-GDd5_GUh.mjs.map +1 -0
  80. package/dist/ui.css +1 -1
  81. package/dist/ui.d.mts +3 -3
  82. package/dist/ui.d.mts.map +1 -1
  83. package/dist/ui.mjs +152 -36
  84. package/dist/ui.mjs.map +1 -1
  85. package/docs/integration.md +73 -5
  86. package/package.json +4 -4
  87. package/dist/authoring-references-DYuOAdVx.mjs.map +0 -1
  88. package/dist/capabilities-DKbNCnBf.mjs +0 -66
  89. package/dist/capabilities-DKbNCnBf.mjs.map +0 -1
  90. package/dist/capabilities-DlC1l6qy.d.mts.map +0 -1
  91. package/dist/constants-CgV4cTg5.d.mts.map +0 -1
  92. package/dist/engine-0AJrv0hI.mjs.map +0 -1
  93. package/dist/index-BNdvGEaq.d.mts.map +0 -1
  94. package/dist/index-BUF-sE8j.d.mts.map +0 -1
  95. package/dist/index-BdXb6jER.d.mts.map +0 -1
  96. package/dist/memory-thread-repository-1ocPOda8.mjs.map +0 -1
  97. package/dist/protocol-DpCYmCjr.mjs.map +0 -1
  98. package/dist/react-DXK5zWNo.mjs.map +0 -1
  99. package/dist/request-context-BBzU3VdG.mjs.map +0 -1
  100. package/dist/tasks-BuLnWrR4.d.mts.map +0 -1
  101. package/dist/thread-handlers-6L8sAreR.d.mts.map +0 -1
  102. package/dist/tools-wgLen05n.mjs.map +0 -1
@@ -1,20 +1,84 @@
1
- import { At as serializeSurveyAssistantError, D as SURVEY_ASSISTANT_ATTACHMENT_PART_TYPE, M as updateSurveyAssistantThreadInputSchema, O as createSurveyAssistantThreadInputSchema, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE } from "./protocol-DpCYmCjr.mjs";
2
- import { t as SurveyAssistantCapabilityMismatchError } from "./capabilities-DKbNCnBf.mjs";
3
- import { i as TurnSurveyDraft } from "./engine-0AJrv0hI.mjs";
1
+ import { A as createSurveyAssistantThreadInputSchema, Mt as serializeSurveyAssistantError, P as updateSurveyAssistantThreadInputSchema, k as SURVEY_ASSISTANT_ATTACHMENT_PART_TYPE, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE } from "./protocol-DATvkr1S.mjs";
2
+ import { s as SurveyAssistantCapabilityMismatchError } from "./form-authoring-DCd9XfXf.mjs";
3
+ import { r as TurnSurveyDraft } from "./engine-CWTuN3o2.mjs";
4
4
  import "./constants-CFUWrRtl.mjs";
5
- import { a as parseSurveyAssistantSnapshot, i as parseSurveyAssistantPreviousSettledVersion, t as buildSurveyAssistantRequestContext } from "./request-context-BBzU3VdG.mjs";
5
+ import { a as parseSurveyAssistantPreviousSettledVersion, i as parseSurveyAssistantPreviousApplyOutcome, o as parseSurveyAssistantSnapshot, t as buildSurveyAssistantRequestContext } from "./request-context-BEjnaaFr.mjs";
6
6
  import { d as readSurveyAssistantRequestJson, f as validateSurveyAssistantMessages, n as SURVEY_ASSISTANT_DEFAULT_REQUEST_LIMITS, u as SurveyAssistantRequestError } from "./request-guardrails-h4t6u8mP.mjs";
7
7
  import { createUIMessageStreamResponse } from "ai";
8
8
  import { handleChatStream } from "@mastra/ai-sdk";
9
9
  import { createHash } from "node:crypto";
10
10
  import { toAISdkMessages } from "@mastra/ai-sdk/ui";
11
+ //#region src/server/execution-timeout.ts
12
+ const timeoutMessages = {
13
+ "first-response": "The survey assistant timed out while waiting for its first response.",
14
+ idle: "The survey assistant timed out after it stopped producing activity.",
15
+ "max-duration": "The survey assistant reached its maximum execution duration."
16
+ };
17
+ const getSurveyAssistantExecutionTimeoutMessage = (kind) => timeoutMessages[kind];
18
+ const isSurveyAssistantExecutionActivityChunk = (chunk) => chunk.type !== "start" && chunk.type !== "start-step" && chunk.type !== "finish" && chunk.type !== "finish-step" && chunk.type !== "abort" && chunk.type !== "error";
19
+ const createSurveyAssistantExecutionTimeout = ({ firstResponseTimeoutMs, idleTimeoutMs, maxDurationMs, requestSignal }) => {
20
+ const timeoutController = new AbortController();
21
+ let activityTimer;
22
+ let hardCapTimer;
23
+ let timeoutKind = null;
24
+ const unrefTimer = (timer) => {
25
+ if (typeof timer === "object" && "unref" in timer) timer.unref();
26
+ };
27
+ const clearActivityTimer = () => {
28
+ if (activityTimer !== void 0) clearTimeout(activityTimer);
29
+ activityTimer = void 0;
30
+ };
31
+ const dispose = () => {
32
+ clearActivityTimer();
33
+ if (hardCapTimer !== void 0) clearTimeout(hardCapTimer);
34
+ hardCapTimer = void 0;
35
+ };
36
+ const abortForTimeout = (kind) => {
37
+ if (timeoutController.signal.aborted || requestSignal.aborted) return;
38
+ timeoutKind = kind;
39
+ dispose();
40
+ timeoutController.abort(new DOMException(getSurveyAssistantExecutionTimeoutMessage(kind), "TimeoutError"));
41
+ };
42
+ const scheduleActivityTimeout = (durationMs, kind) => {
43
+ clearActivityTimer();
44
+ activityTimer = setTimeout(() => abortForTimeout(kind), durationMs);
45
+ unrefTimer(activityTimer);
46
+ };
47
+ if (!requestSignal.aborted) {
48
+ hardCapTimer = setTimeout(() => abortForTimeout("max-duration"), maxDurationMs);
49
+ unrefTimer(hardCapTimer);
50
+ scheduleActivityTimeout(firstResponseTimeoutMs, "first-response");
51
+ }
52
+ const signal = AbortSignal.any([requestSignal, timeoutController.signal]);
53
+ return {
54
+ signal,
55
+ get timeoutKind() {
56
+ return timeoutKind;
57
+ },
58
+ dispose,
59
+ recordActivity() {
60
+ if (signal.aborted) return;
61
+ scheduleActivityTimeout(idleTimeoutMs, "idle");
62
+ }
63
+ };
64
+ };
65
+ //#endregion
11
66
  //#region src/server/turn-stream.ts
12
67
  const createTurnFinalChunk = (turnFinal) => ({
13
68
  type: SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE,
14
69
  id: turnFinal.turnId,
15
70
  data: turnFinal
16
71
  });
17
- const createSurveyAssistantTurnStream = ({ turnDraft, onSettled, onUnexpectedError = () => "The survey assistant stream ended unexpectedly.", signal, stream }) => {
72
+ const getFinishTerminationReason = (finishReason) => {
73
+ switch (finishReason) {
74
+ case "tool-calls": return "max-steps";
75
+ case "length": return "length-limit";
76
+ case "content-filter": return "content-filter";
77
+ case "error": return "provider-error";
78
+ default: return "incomplete-response";
79
+ }
80
+ };
81
+ const createSurveyAssistantTurnStream = ({ turnDraft, getAbortErrorText, getAbortTerminationReason, onActivity, onSettled, onUnexpectedError = () => "The survey assistant stream ended unexpectedly.", signal, stream, turnStartedAt }) => {
18
82
  const reader = stream.getReader();
19
83
  let settled = false;
20
84
  const settle = () => {
@@ -26,16 +90,36 @@ const createSurveyAssistantTurnStream = ({ turnDraft, onSettled, onUnexpectedErr
26
90
  async start(controller) {
27
91
  let emittedTurnFinal = false;
28
92
  let sawFinish = false;
93
+ let emittedAbortError = false;
29
94
  let finishReason;
30
- const emitTurnFinal = (status) => {
95
+ const emitTurnFinal = (status, terminationReason) => {
31
96
  if (emittedTurnFinal) return;
32
97
  emittedTurnFinal = true;
33
- controller.enqueue(createTurnFinalChunk(turnDraft.finalize(status)));
98
+ const completedAt = Date.now();
99
+ controller.enqueue(createTurnFinalChunk(turnDraft.finalize(status, new Date(completedAt).toISOString(), {
100
+ ...turnStartedAt === void 0 ? {} : {
101
+ startedAt: new Date(turnStartedAt).toISOString(),
102
+ durationMs: Math.max(0, completedAt - turnStartedAt)
103
+ },
104
+ ...terminationReason ? { terminationReason } : {}
105
+ })));
106
+ };
107
+ const emitAbortOutcome = () => {
108
+ const errorText = getAbortErrorText?.();
109
+ emitTurnFinal(errorText ? "failed" : "aborted", getAbortTerminationReason?.() ?? (errorText ? "incomplete-response" : "client-abort"));
110
+ if (errorText && !emittedAbortError) {
111
+ emittedAbortError = true;
112
+ controller.enqueue({
113
+ type: "error",
114
+ errorText
115
+ });
116
+ }
34
117
  };
35
118
  try {
36
119
  while (true) {
37
120
  const { done, value } = await reader.read();
38
121
  if (done) break;
122
+ if (isSurveyAssistantExecutionActivityChunk(value)) onActivity?.();
39
123
  if (value.type === SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE) {
40
124
  emitTurnFinal("failed");
41
125
  controller.enqueue({
@@ -46,13 +130,14 @@ const createSurveyAssistantTurnStream = ({ turnDraft, onSettled, onUnexpectedErr
46
130
  break;
47
131
  }
48
132
  if (value.type === "error") {
49
- emitTurnFinal("failed");
133
+ emitTurnFinal("failed", "provider-error");
50
134
  controller.enqueue(value);
51
135
  continue;
52
136
  }
53
137
  if (value.type === "abort") {
54
- emitTurnFinal("aborted");
55
- controller.enqueue(value);
138
+ const timeoutErrorText = getAbortErrorText?.();
139
+ emitAbortOutcome();
140
+ if (!timeoutErrorText) controller.enqueue(value);
56
141
  continue;
57
142
  }
58
143
  if (value.type === "finish") {
@@ -61,11 +146,13 @@ const createSurveyAssistantTurnStream = ({ turnDraft, onSettled, onUnexpectedErr
61
146
  }
62
147
  controller.enqueue(value);
63
148
  }
64
- if (!emittedTurnFinal) emitTurnFinal(signal?.aborted ? "aborted" : sawFinish && (finishReason === void 0 || finishReason === "stop") ? "completed" : "failed");
149
+ if (!emittedTurnFinal) if (signal?.aborted) emitAbortOutcome();
150
+ else emitTurnFinal(sawFinish && (finishReason === void 0 || finishReason === "stop") ? "completed" : "failed", sawFinish && finishReason !== void 0 && finishReason !== "stop" ? getFinishTerminationReason(finishReason) : !sawFinish ? "incomplete-response" : void 0);
65
151
  controller.close();
66
152
  } catch (error) {
67
153
  try {
68
- emitTurnFinal(signal?.aborted ? "aborted" : "failed");
154
+ if (signal?.aborted) emitAbortOutcome();
155
+ else emitTurnFinal("failed", "stream-error");
69
156
  if (!signal?.aborted) controller.enqueue({
70
157
  type: "error",
71
158
  errorText: onUnexpectedError(error)
@@ -78,7 +165,14 @@ const createSurveyAssistantTurnStream = ({ turnDraft, onSettled, onUnexpectedErr
78
165
  }
79
166
  },
80
167
  async cancel(reason) {
81
- turnDraft.finalize("aborted");
168
+ const completedAt = Date.now();
169
+ turnDraft.finalize("aborted", new Date(completedAt).toISOString(), {
170
+ ...turnStartedAt === void 0 ? {} : {
171
+ startedAt: new Date(turnStartedAt).toISOString(),
172
+ durationMs: Math.max(0, completedAt - turnStartedAt)
173
+ },
174
+ terminationReason: "client-abort"
175
+ });
82
176
  settle();
83
177
  await reader.cancel(reason);
84
178
  }
@@ -208,9 +302,18 @@ const loadSurveyAssistantDocuments = async ({ documents, repository, resourceId,
208
302
  //#region src/server/handler.ts
209
303
  const DEFAULT_MAX_STEPS = 48;
210
304
  const DEFAULT_MAX_CONCURRENT_REQUESTS = 4;
211
- const DEFAULT_MAX_DURATION_MS = 180 * 1e3;
305
+ const DEFAULT_FIRST_RESPONSE_TIMEOUT_MS = 900 * 1e3;
306
+ const DEFAULT_IDLE_TIMEOUT_MS = 300 * 1e3;
307
+ const DEFAULT_MAX_DURATION_MS = 3600 * 1e3;
212
308
  const MAX_USER_ERROR_MESSAGE_LENGTH = 700;
213
309
  const MAX_ERROR_CAUSE_DEPTH = 5;
310
+ const getTimeoutTerminationReason = (kind) => {
311
+ switch (kind) {
312
+ case "first-response": return "first-response-timeout";
313
+ case "idle": return "idle-timeout";
314
+ case "max-duration": return "max-duration";
315
+ }
316
+ };
214
317
  var SurveyAssistantAuthorizationError = class extends Error {
215
318
  status;
216
319
  constructor(message = "The survey assistant request is not authorized.", status = 403) {
@@ -237,10 +340,35 @@ const validateAuthorizedIdentity = (identity) => {
237
340
  const validateModelSelection = (selection) => {
238
341
  if (!selection) return null;
239
342
  const id = optionalRequestedId(selection.id);
240
- const model = optionalRequestedId(selection.model);
241
- return id && model ? {
343
+ const modelValue = selection.model;
344
+ const stringModel = typeof modelValue === "string" ? optionalRequestedId(modelValue) : void 0;
345
+ const objectModel = (() => {
346
+ if (!isRecord(modelValue)) return void 0;
347
+ const url = modelValue.url;
348
+ const apiKey = modelValue.apiKey;
349
+ const headers = modelValue.headers;
350
+ if (url !== void 0 && typeof url !== "string" || apiKey !== void 0 && typeof apiKey !== "string" || headers !== void 0 && (!isRecord(headers) || Object.values(headers).some((value) => typeof value !== "string"))) return;
351
+ const shared = {
352
+ ...url === void 0 ? {} : { url },
353
+ ...apiKey === void 0 ? {} : { apiKey },
354
+ ...headers === void 0 ? {} : { headers }
355
+ };
356
+ const compatibleId = optionalRequestedId(modelValue.id);
357
+ if (compatibleId) return {
358
+ id: compatibleId,
359
+ ...shared
360
+ };
361
+ const providerId = optionalRequestedId(modelValue.providerId);
362
+ const modelId = optionalRequestedId(modelValue.modelId);
363
+ if (providerId && modelId) return {
364
+ providerId,
365
+ modelId,
366
+ ...shared
367
+ };
368
+ })();
369
+ return id && (stringModel || objectModel) ? {
242
370
  id,
243
- model
371
+ model: stringModel ?? objectModel
244
372
  } : null;
245
373
  };
246
374
  const readNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
@@ -354,6 +482,8 @@ const createSurveyAssistantChatHandler = (options) => {
354
482
  for (const [name, value] of Object.entries(requestLimits)) if (name !== "acceptedAttachmentTypes" && (!Number.isSafeInteger(value) || value <= 0)) throw new Error(`Survey assistant request limit "${name}" must be a positive integer.`);
355
483
  if (typeof requestLimits.acceptedAttachmentTypes?.has !== "function") throw new Error("Survey assistant accepted attachment types must be a set.");
356
484
  const maxConcurrentRequests = Number.isInteger(options.maxConcurrentRequests) && (options.maxConcurrentRequests ?? 0) > 0 ? options.maxConcurrentRequests : DEFAULT_MAX_CONCURRENT_REQUESTS;
485
+ const firstResponseTimeoutMs = Number.isFinite(options.firstResponseTimeoutMs) && (options.firstResponseTimeoutMs ?? 0) > 0 ? options.firstResponseTimeoutMs : DEFAULT_FIRST_RESPONSE_TIMEOUT_MS;
486
+ const idleTimeoutMs = Number.isFinite(options.idleTimeoutMs) && (options.idleTimeoutMs ?? 0) > 0 ? options.idleTimeoutMs : DEFAULT_IDLE_TIMEOUT_MS;
357
487
  const maxSteps = Number.isInteger(options.maxSteps) && (options.maxSteps ?? 0) > 0 ? options.maxSteps : DEFAULT_MAX_STEPS;
358
488
  const maxDurationMs = Number.isFinite(options.maxDurationMs) && (options.maxDurationMs ?? 0) > 0 ? options.maxDurationMs : DEFAULT_MAX_DURATION_MS;
359
489
  let activeRequestCount = 0;
@@ -431,9 +561,11 @@ const createSurveyAssistantChatHandler = (options) => {
431
561
  }
432
562
  let snapshot;
433
563
  let previousSettledVersion;
564
+ let previousApplyOutcome;
434
565
  try {
435
566
  snapshot = parseSurveyAssistantSnapshot(params.snapshot);
436
567
  previousSettledVersion = parseSurveyAssistantPreviousSettledVersion(params.previousSettledVersion);
568
+ previousApplyOutcome = parseSurveyAssistantPreviousApplyOutcome(params.previousApplyOutcome);
437
569
  } catch {
438
570
  return Response.json({
439
571
  code: "request_failed",
@@ -497,6 +629,7 @@ const createSurveyAssistantChatHandler = (options) => {
497
629
  identity,
498
630
  snapshot,
499
631
  previousSettledVersion,
632
+ previousApplyOutcome,
500
633
  trustedCapabilities: options.trustedCapabilities,
501
634
  attachmentAccess,
502
635
  modelAttachments,
@@ -528,8 +661,22 @@ const createSurveyAssistantChatHandler = (options) => {
528
661
  surveyId: identity.surveyId,
529
662
  threadId: identity.threadId
530
663
  };
531
- const timeoutSignal = AbortSignal.timeout(maxDurationMs);
532
- const executionSignal = AbortSignal.any([request.signal, timeoutSignal]);
664
+ const executionStartedAt = Date.now();
665
+ const executionTimeout = createSurveyAssistantExecutionTimeout({
666
+ firstResponseTimeoutMs,
667
+ idleTimeoutMs,
668
+ maxDurationMs,
669
+ requestSignal: request.signal
670
+ });
671
+ const executionSignal = executionTimeout.signal;
672
+ const finalizeExecutionTurn = (status, terminationReason) => {
673
+ const completedAt = Date.now();
674
+ return turnDraft.finalize(status, new Date(completedAt).toISOString(), {
675
+ startedAt: new Date(executionStartedAt).toISOString(),
676
+ durationMs: Math.max(0, completedAt - executionStartedAt),
677
+ ...terminationReason ? { terminationReason } : {}
678
+ });
679
+ };
533
680
  const handleStreamError = (error) => {
534
681
  options.onStreamError?.(error, streamErrorContext);
535
682
  return options.formatStreamError?.(error, streamErrorContext) ?? formatSurveyAssistantStreamError(error);
@@ -547,10 +694,10 @@ const createSurveyAssistantChatHandler = (options) => {
547
694
  runId: turnDraft.turnId,
548
695
  abortSignal: executionSignal,
549
696
  onAbort: () => {
550
- turnDraft.finalize("aborted");
697
+ finalizeExecutionTurn(executionTimeout.timeoutKind ? "failed" : "aborted", executionTimeout.timeoutKind ? getTimeoutTerminationReason(executionTimeout.timeoutKind) : "client-abort");
551
698
  },
552
699
  onError: () => {
553
- turnDraft.finalize("failed");
700
+ finalizeExecutionTurn("failed", "provider-error");
554
701
  },
555
702
  memory: {
556
703
  thread: identity.threadId,
@@ -567,22 +714,29 @@ const createSurveyAssistantChatHandler = (options) => {
567
714
  recordTurnStreamPart(metrics, part);
568
715
  },
569
716
  onError: (error) => {
570
- turnDraft.finalize("failed");
717
+ finalizeExecutionTurn("failed", "provider-error");
571
718
  return handleStreamError(error);
572
719
  }
573
720
  });
574
721
  } catch (error) {
575
- turnDraft.finalize(executionSignal.aborted ? "aborted" : "failed");
722
+ finalizeExecutionTurn(executionTimeout.timeoutKind ? "failed" : executionSignal.aborted ? "aborted" : "failed", executionTimeout.timeoutKind ? getTimeoutTerminationReason(executionTimeout.timeoutKind) : executionSignal.aborted ? "client-abort" : "provider-error");
723
+ executionTimeout.dispose();
576
724
  releaseRequestSlot();
577
- return Response.json({ error: handleStreamError(error) }, { status: 503 });
725
+ return Response.json({ error: executionTimeout.timeoutKind ? getSurveyAssistantExecutionTimeoutMessage(executionTimeout.timeoutKind) : handleStreamError(error) }, { status: 503 });
578
726
  }
579
727
  return createUIMessageStreamResponse({ stream: createSurveyAssistantTurnStream({
580
728
  stream,
581
729
  turnDraft,
582
730
  signal: executionSignal,
731
+ getAbortErrorText: () => executionTimeout.timeoutKind ? getSurveyAssistantExecutionTimeoutMessage(executionTimeout.timeoutKind) : void 0,
732
+ getAbortTerminationReason: () => executionTimeout.timeoutKind ? getTimeoutTerminationReason(executionTimeout.timeoutKind) : request.signal.aborted ? "client-abort" : void 0,
733
+ onActivity: executionTimeout.recordActivity,
583
734
  onUnexpectedError: handleStreamError,
584
735
  onSettled: () => {
736
+ executionTimeout.dispose();
585
737
  releaseRequestSlot();
738
+ metrics.durationMs = Date.now() - executionStartedAt;
739
+ metrics.terminationReason = turnDraft.final?.terminationReason;
586
740
  try {
587
741
  options.onTurnMetrics?.({
588
742
  identity,
@@ -595,7 +749,8 @@ const createSurveyAssistantChatHandler = (options) => {
595
749
  options.onStreamError?.(error, streamErrorContext);
596
750
  } catch {}
597
751
  }
598
- }
752
+ },
753
+ turnStartedAt: executionStartedAt
599
754
  }) });
600
755
  };
601
756
  };
@@ -784,4 +939,4 @@ const createMastraMemoryThreadRepository = ({ getMemory, maxMessagesPerTranscrip
784
939
  //#endregion
785
940
  export { describeSurveyAssistantStreamError as a, loadSurveyAssistantDocuments as c, removeHistoricalSurveyAssistantAttachments as d, replaceCurrentSurveyAssistantAttachmentsWithReferences as f, createSurveyAssistantChatHandler as i, loadSurveyAssistantThreadAttachments as l, createSurveyAssistantThreadHandlers as n, formatSurveyAssistantStreamError as o, createSurveyAssistantTurnStream as p, SurveyAssistantAuthorizationError as r, getSurveyAssistantReplayableDocuments as s, createMastraMemoryThreadRepository as t, registerSurveyAssistantThreadAttachments as u };
786
941
 
787
- //# sourceMappingURL=memory-thread-repository-1ocPOda8.mjs.map
942
+ //# sourceMappingURL=memory-thread-repository-acbz6HZJ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-thread-repository-acbz6HZJ.mjs","names":[],"sources":["../src/server/execution-timeout.ts","../src/server/turn-stream.ts","../src/server/thread-documents.ts","../src/server/handler.ts","../src/server/thread-handlers.ts","../src/server/memory-thread-repository.ts"],"sourcesContent":["import type { UIMessageChunk } from \"ai\";\n\nexport type SurveyAssistantExecutionTimeoutKind = \"first-response\" | \"idle\" | \"max-duration\";\n\nexport interface SurveyAssistantExecutionTimeoutOptions {\n firstResponseTimeoutMs: number;\n idleTimeoutMs: number;\n maxDurationMs: number;\n requestSignal: AbortSignal;\n}\n\nexport interface SurveyAssistantExecutionTimeout {\n readonly signal: AbortSignal;\n readonly timeoutKind: SurveyAssistantExecutionTimeoutKind | null;\n dispose(): void;\n recordActivity(): void;\n}\n\nconst timeoutMessages: Record<SurveyAssistantExecutionTimeoutKind, string> = {\n \"first-response\": \"The survey assistant timed out while waiting for its first response.\",\n idle: \"The survey assistant timed out after it stopped producing activity.\",\n \"max-duration\": \"The survey assistant reached its maximum execution duration.\",\n};\n\nexport const getSurveyAssistantExecutionTimeoutMessage = (\n kind: SurveyAssistantExecutionTimeoutKind,\n) => timeoutMessages[kind];\n\nexport const isSurveyAssistantExecutionActivityChunk = (chunk: UIMessageChunk): boolean =>\n chunk.type !== \"start\" &&\n chunk.type !== \"start-step\" &&\n chunk.type !== \"finish\" &&\n chunk.type !== \"finish-step\" &&\n chunk.type !== \"abort\" &&\n chunk.type !== \"error\";\n\nexport const createSurveyAssistantExecutionTimeout = ({\n firstResponseTimeoutMs,\n idleTimeoutMs,\n maxDurationMs,\n requestSignal,\n}: SurveyAssistantExecutionTimeoutOptions): SurveyAssistantExecutionTimeout => {\n const timeoutController = new AbortController();\n let activityTimer: ReturnType<typeof setTimeout> | undefined;\n let hardCapTimer: ReturnType<typeof setTimeout> | undefined;\n let timeoutKind: SurveyAssistantExecutionTimeoutKind | null = null;\n\n const unrefTimer = (timer: ReturnType<typeof setTimeout>) => {\n if (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n };\n\n const clearActivityTimer = () => {\n if (activityTimer !== undefined) clearTimeout(activityTimer);\n activityTimer = undefined;\n };\n const dispose = () => {\n clearActivityTimer();\n if (hardCapTimer !== undefined) clearTimeout(hardCapTimer);\n hardCapTimer = undefined;\n };\n const abortForTimeout = (kind: SurveyAssistantExecutionTimeoutKind) => {\n if (timeoutController.signal.aborted || requestSignal.aborted) return;\n timeoutKind = kind;\n dispose();\n timeoutController.abort(\n new DOMException(getSurveyAssistantExecutionTimeoutMessage(kind), \"TimeoutError\"),\n );\n };\n const scheduleActivityTimeout = (\n durationMs: number,\n kind: Extract<SurveyAssistantExecutionTimeoutKind, \"first-response\" | \"idle\">,\n ) => {\n clearActivityTimer();\n activityTimer = setTimeout(() => abortForTimeout(kind), durationMs);\n unrefTimer(activityTimer);\n };\n\n if (!requestSignal.aborted) {\n hardCapTimer = setTimeout(() => abortForTimeout(\"max-duration\"), maxDurationMs);\n unrefTimer(hardCapTimer);\n scheduleActivityTimeout(firstResponseTimeoutMs, \"first-response\");\n }\n\n const signal = AbortSignal.any([requestSignal, timeoutController.signal]);\n\n return {\n signal,\n get timeoutKind() {\n return timeoutKind;\n },\n dispose,\n recordActivity() {\n if (signal.aborted) return;\n scheduleActivityTimeout(idleTimeoutMs, \"idle\");\n },\n };\n};\n","import {\n SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE,\n type SurveyAssistantTurnFinal,\n type SurveyAssistantTurnTerminationReason,\n} from \"../protocol\";\nimport type { TurnSurveyDraft } from \"../engine\";\nimport type { UIMessageChunk } from \"ai\";\nimport { isSurveyAssistantExecutionActivityChunk } from \"./execution-timeout\";\n\nconst createTurnFinalChunk = (turnFinal: SurveyAssistantTurnFinal): UIMessageChunk => ({\n type: SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE,\n id: turnFinal.turnId,\n data: turnFinal,\n});\n\nexport interface SurveyAssistantTurnStreamOptions {\n stream: ReadableStream<UIMessageChunk>;\n turnDraft: TurnSurveyDraft;\n signal?: AbortSignal;\n onUnexpectedError?: (error: unknown) => string;\n onActivity?: () => void;\n onSettled?: () => void;\n getAbortErrorText?: () => string | undefined;\n getAbortTerminationReason?: () => SurveyAssistantTurnTerminationReason | undefined;\n turnStartedAt?: number;\n}\n\nconst getFinishTerminationReason = (\n finishReason: Extract<UIMessageChunk, { type: \"finish\" }>[\"finishReason\"],\n): SurveyAssistantTurnTerminationReason => {\n switch (finishReason) {\n // The AI SDK reports the agent loop's step cap this way; it isn't a literal tool-call error.\n case \"tool-calls\":\n return \"max-steps\";\n case \"length\":\n return \"length-limit\";\n case \"content-filter\":\n return \"content-filter\";\n case \"error\":\n return \"provider-error\";\n default:\n return \"incomplete-response\";\n }\n};\n\nexport const createSurveyAssistantTurnStream = ({\n turnDraft,\n getAbortErrorText,\n getAbortTerminationReason,\n onActivity,\n onSettled,\n onUnexpectedError = () => \"The survey assistant stream ended unexpectedly.\",\n signal,\n stream,\n turnStartedAt,\n}: SurveyAssistantTurnStreamOptions): ReadableStream<UIMessageChunk> => {\n const reader = stream.getReader();\n let settled = false;\n\n const settle = () => {\n if (settled) {\n return;\n }\n settled = true;\n onSettled?.();\n };\n\n return new ReadableStream<UIMessageChunk>({\n async start(controller) {\n let emittedTurnFinal = false;\n let sawFinish = false;\n let emittedAbortError = false;\n let finishReason: Extract<UIMessageChunk, { type: \"finish\" }>[\"finishReason\"];\n\n const emitTurnFinal = (\n status: SurveyAssistantTurnFinal[\"status\"],\n terminationReason?: SurveyAssistantTurnTerminationReason,\n ) => {\n if (emittedTurnFinal) {\n return;\n }\n emittedTurnFinal = true;\n const completedAt = Date.now();\n controller.enqueue(\n createTurnFinalChunk(\n turnDraft.finalize(status, new Date(completedAt).toISOString(), {\n ...(turnStartedAt === undefined\n ? {}\n : {\n startedAt: new Date(turnStartedAt).toISOString(),\n durationMs: Math.max(0, completedAt - turnStartedAt),\n }),\n ...(terminationReason ? { terminationReason } : {}),\n }),\n ),\n );\n };\n const emitAbortOutcome = () => {\n const errorText = getAbortErrorText?.();\n emitTurnFinal(\n errorText ? \"failed\" : \"aborted\",\n getAbortTerminationReason?.() ?? (errorText ? \"incomplete-response\" : \"client-abort\"),\n );\n if (errorText && !emittedAbortError) {\n emittedAbortError = true;\n controller.enqueue({ type: \"error\", errorText });\n }\n };\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n if (isSurveyAssistantExecutionActivityChunk(value)) onActivity?.();\n\n if (value.type === SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE) {\n emitTurnFinal(\"failed\");\n controller.enqueue({\n type: \"error\",\n errorText: \"The survey assistant returned an invalid duplicate turn final.\",\n });\n await reader.cancel(\"duplicate turn final\");\n break;\n }\n if (value.type === \"error\") {\n emitTurnFinal(\"failed\", \"provider-error\");\n controller.enqueue(value);\n continue;\n }\n if (value.type === \"abort\") {\n const timeoutErrorText = getAbortErrorText?.();\n emitAbortOutcome();\n if (!timeoutErrorText) controller.enqueue(value);\n continue;\n }\n if (value.type === \"finish\") {\n sawFinish = true;\n finishReason = value.finishReason;\n }\n controller.enqueue(value);\n }\n\n if (!emittedTurnFinal) {\n if (signal?.aborted) {\n emitAbortOutcome();\n } else {\n emitTurnFinal(\n sawFinish && (finishReason === undefined || finishReason === \"stop\")\n ? \"completed\"\n : \"failed\",\n sawFinish && finishReason !== undefined && finishReason !== \"stop\"\n ? getFinishTerminationReason(finishReason)\n : !sawFinish\n ? \"incomplete-response\"\n : undefined,\n );\n }\n }\n controller.close();\n } catch (error) {\n try {\n if (signal?.aborted) emitAbortOutcome();\n else emitTurnFinal(\"failed\", \"stream-error\");\n if (!signal?.aborted) {\n controller.enqueue({ type: \"error\", errorText: onUnexpectedError(error) });\n }\n controller.close();\n } catch {\n // The client disconnected; finalization still occurred server-side.\n }\n } finally {\n reader.releaseLock();\n settle();\n }\n },\n async cancel(reason) {\n const completedAt = Date.now();\n turnDraft.finalize(\"aborted\", new Date(completedAt).toISOString(), {\n ...(turnStartedAt === undefined\n ? {}\n : {\n startedAt: new Date(turnStartedAt).toISOString(),\n durationMs: Math.max(0, completedAt - turnStartedAt),\n }),\n terminationReason: \"client-abort\",\n });\n settle();\n await reader.cancel(reason);\n },\n });\n};\n","import type { UIMessage } from \"ai\";\nimport { createHash } from \"node:crypto\";\nimport {\n SURVEY_ASSISTANT_ATTACHMENT_PART_TYPE,\n type SurveyAssistantAttachmentReference,\n} from \"../protocol\";\n\nexport interface SurveyAssistantThreadDocument {\n id: string;\n name: string;\n mediaType: string;\n bytes: number;\n contentHash: string;\n createdAt: string;\n}\n\nexport interface SurveyAssistantThreadDocumentContent extends SurveyAssistantThreadDocument {\n data: string;\n}\n\nexport interface SurveyAssistantModelAttachment {\n filename: string;\n mediaType: string;\n data: string;\n contentHash: string;\n}\n\nexport interface SurveyAssistantAttachmentAccess {\n documents: SurveyAssistantThreadDocument[];\n /** Attachments submitted in the current user message; already present as model context. */\n currentDocumentIds?: string[];\n selectedAttachments: SurveyAssistantModelAttachment[];\n load(documentIds: string[]): Promise<SurveyAssistantModelAttachment[]>;\n}\n\nexport interface SurveyAssistantThreadDocumentRepository {\n put(input: {\n resourceId: string;\n threadId: string;\n name: string;\n mediaType: string;\n data: string;\n bytes: number;\n }): Promise<SurveyAssistantThreadDocument>;\n list(input: { resourceId: string; threadId: string }): Promise<SurveyAssistantThreadDocument[]>;\n read(input: {\n resourceId: string;\n threadId: string;\n documentId: string;\n }): Promise<SurveyAssistantThreadDocumentContent | null>;\n deleteThread(input: { resourceId: string; threadId: string }): Promise<void>;\n}\n\nconst parseFileDataUrl = (url: string) => {\n const match = /^data:([^;,]+);base64,([A-Za-z0-9+/]*={0,2})$/.exec(url);\n return match ? { mediaType: match[1], data: match[2] } : null;\n};\n\nconst getBase64Bytes = (data: string) => {\n const padding = data.endsWith(\"==\") ? 2 : data.endsWith(\"=\") ? 1 : 0;\n return Math.max(0, Math.floor((data.length * 3) / 4) - padding);\n};\n\nconst getAttachmentContentHash = (data: string) => createHash(\"sha256\").update(data).digest(\"hex\");\n\nconst createAttachmentReferencePart = ({\n document,\n filename,\n mediaType,\n parsedData,\n}: {\n document?: SurveyAssistantThreadDocument;\n filename?: string;\n mediaType: string;\n parsedData?: string;\n}) => ({\n type: SURVEY_ASSISTANT_ATTACHMENT_PART_TYPE,\n data: {\n ...(document ? { documentId: document.id } : {}),\n filename: filename?.trim() || document?.name || \"Attached document\",\n mediaType: document?.mediaType || mediaType,\n bytes: document?.bytes ?? (parsedData ? getBase64Bytes(parsedData) : 0),\n } satisfies SurveyAssistantAttachmentReference,\n});\n\nconst createDocumentIndex = (documents: SurveyAssistantThreadDocument[]) =>\n new Map(\n documents.map((document) => [`${document.mediaType}\\u0000${document.contentHash}`, document]),\n );\n\n/**\n * Replaces current-turn file data with small repository references before the\n * message is handed to Mastra for persistence. The provider-bound attachment\n * processor re-injects the authorized repository copy transiently.\n */\nexport const replaceCurrentSurveyAssistantAttachmentsWithReferences = ({\n documents,\n messages,\n}: {\n documents: SurveyAssistantThreadDocument[];\n messages: UIMessage[];\n}): UIMessage[] => {\n const current = getCurrentUserMessage(messages);\n if (!current) return messages;\n const documentIndex = createDocumentIndex(documents);\n\n return messages.map((message) => {\n if (message !== current) return message;\n let changed = false;\n const parts = message.parts.map((part) => {\n if (part.type !== \"file\") return part;\n changed = true;\n const parsed = typeof part.url === \"string\" ? parseFileDataUrl(part.url) : null;\n const mediaType = parsed?.mediaType || part.mediaType;\n const document = parsed\n ? documentIndex.get(`${mediaType}\\u0000${getAttachmentContentHash(parsed.data)}`)\n : undefined;\n return createAttachmentReferencePart({\n document,\n filename: part.filename,\n mediaType,\n parsedData: parsed?.data,\n });\n });\n return changed ? { ...message, parts } : message;\n }) as UIMessage[];\n};\n\nexport const registerSurveyAssistantThreadAttachments = async ({\n messages,\n repository,\n resourceId,\n threadId,\n}: {\n messages: UIMessage[];\n repository: SurveyAssistantThreadDocumentRepository;\n resourceId: string;\n threadId: string;\n}) => {\n const registered: SurveyAssistantThreadDocument[] = [];\n\n const currentMessage = getCurrentUserMessage(messages);\n for (const message of currentMessage ? [currentMessage] : []) {\n for (const part of message.parts) {\n if (part.type !== \"file\" || typeof part.url !== \"string\") continue;\n const parsed = parseFileDataUrl(part.url);\n if (!parsed) continue;\n\n registered.push(\n await repository.put({\n resourceId,\n threadId,\n name: part.filename?.trim() || \"Attached document\",\n mediaType: parsed.mediaType,\n data: parsed.data,\n bytes: getBase64Bytes(parsed.data),\n }),\n );\n }\n }\n\n return registered;\n};\n\nconst getCurrentUserMessage = (messages: UIMessage[]) => {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n const message = messages[index];\n if (message?.role === \"user\") return message;\n }\n return undefined;\n};\n\nexport const removeHistoricalSurveyAssistantAttachments = (messages: UIMessage[]) => {\n const current = getCurrentUserMessage(messages);\n return messages.map((message) => {\n if (message === current) return message;\n const parts = message.parts.filter((part) => part.type !== \"file\");\n return parts.length === message.parts.length ? message : { ...message, parts };\n });\n};\n\n/**\n * Excludes the exact repository documents already loaded for the current turn.\n * Message parts are references by this stage and are not a deduplication source.\n */\nexport const getSurveyAssistantReplayableDocuments = (\n documents: SurveyAssistantThreadDocument[],\n currentDocumentIds: ReadonlySet<string>,\n) => documents.filter((document) => !currentDocumentIds.has(document.id));\n\nexport const loadSurveyAssistantThreadAttachments = async ({\n currentDocumentIds = new Set<string>(),\n documents,\n repository,\n resourceId,\n threadId,\n}: {\n currentDocumentIds?: ReadonlySet<string>;\n documents: SurveyAssistantThreadDocument[];\n repository: SurveyAssistantThreadDocumentRepository;\n resourceId: string;\n threadId: string;\n}): Promise<SurveyAssistantModelAttachment[]> => {\n const replayableDocuments = getSurveyAssistantReplayableDocuments(documents, currentDocumentIds);\n\n return loadSurveyAssistantDocuments({\n documents: replayableDocuments,\n repository,\n resourceId,\n threadId,\n });\n};\n\nexport const loadSurveyAssistantDocuments = async ({\n documents,\n repository,\n resourceId,\n threadId,\n}: {\n documents: SurveyAssistantThreadDocument[];\n repository: SurveyAssistantThreadDocumentRepository;\n resourceId: string;\n threadId: string;\n}): Promise<SurveyAssistantModelAttachment[]> => {\n const attachments: SurveyAssistantModelAttachment[] = [];\n for (const document of documents) {\n const content = await repository.read({\n resourceId,\n threadId,\n documentId: document.id,\n });\n if (!content) continue;\n attachments.push({\n filename: content.name,\n mediaType: content.mediaType,\n data: content.data,\n contentHash: content.contentHash,\n });\n }\n\n return attachments;\n};\n","import { handleChatStream } from \"@mastra/ai-sdk\";\nimport type { AgentExecutionOptions } from \"@mastra/core/agent\";\nimport type { Mastra } from \"@mastra/core/mastra\";\nimport { createUIMessageStreamResponse, type UIMessage, type UIMessageChunk } from \"ai\";\nimport {\n SurveyAssistantCapabilityMismatchError,\n TurnSurveyDraft,\n type SurveyAssistantCapabilitySet,\n} from \"../engine\";\nimport {\n serializeSurveyAssistantError,\n type SurveyAssistantErrorCode,\n type SurveyAssistantTurnTerminationReason,\n type SurveyDocumentSnapshot,\n} from \"../protocol\";\nimport {\n buildSurveyAssistantRequestContext,\n parseSurveyAssistantPreviousApplyOutcome,\n parseSurveyAssistantPreviousSettledVersion,\n parseSurveyAssistantSnapshot,\n type SurveyAssistantModelSelection,\n type SurveyAssistantIdentityContext,\n} from \"./request-context\";\nimport { SURVEY_ASSISTANT_AGENT_ID } from \"./constants\";\nimport {\n readSurveyAssistantRequestJson,\n SurveyAssistantRequestError,\n SURVEY_ASSISTANT_DEFAULT_REQUEST_LIMITS,\n type SurveyAssistantRequestLimits,\n validateSurveyAssistantMessages,\n} from \"./request-guardrails\";\nimport { createSurveyAssistantTurnStream } from \"./turn-stream\";\nimport {\n createSurveyAssistantExecutionTimeout,\n getSurveyAssistantExecutionTimeoutMessage,\n type SurveyAssistantExecutionTimeoutKind,\n} from \"./execution-timeout\";\nimport {\n registerSurveyAssistantThreadAttachments,\n loadSurveyAssistantDocuments,\n getSurveyAssistantReplayableDocuments,\n removeHistoricalSurveyAssistantAttachments,\n replaceCurrentSurveyAssistantAttachmentsWithReferences,\n type SurveyAssistantAttachmentAccess,\n type SurveyAssistantModelAttachment,\n type SurveyAssistantThreadDocumentRepository,\n} from \"./thread-documents\";\n\nconst DEFAULT_MAX_STEPS = 48;\nconst DEFAULT_MAX_CONCURRENT_REQUESTS = 4;\nconst DEFAULT_FIRST_RESPONSE_TIMEOUT_MS = 15 * 60 * 1_000;\nconst DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1_000;\nconst DEFAULT_MAX_DURATION_MS = 60 * 60 * 1_000;\nconst MAX_USER_ERROR_MESSAGE_LENGTH = 700;\nconst MAX_ERROR_CAUSE_DEPTH = 5;\n\ntype ProviderOptions = AgentExecutionOptions[\"providerOptions\"];\n\nconst getTimeoutTerminationReason = (\n kind: SurveyAssistantExecutionTimeoutKind,\n): SurveyAssistantTurnTerminationReason => {\n switch (kind) {\n case \"first-response\":\n return \"first-response-timeout\";\n case \"idle\":\n return \"idle-timeout\";\n case \"max-duration\":\n return \"max-duration\";\n }\n};\n\nexport interface SurveyAssistantAuthorizationInput {\n request: Request;\n requestedResourceId?: string;\n requestedThreadId?: string;\n requestedSurveyId?: string;\n}\n\nexport type SurveyAssistantAuthorizedIdentity = SurveyAssistantIdentityContext;\n\nexport type SurveyAssistantAuthorize = (\n input: SurveyAssistantAuthorizationInput,\n) => Promise<SurveyAssistantAuthorizedIdentity> | SurveyAssistantAuthorizedIdentity;\n\nexport interface SurveyAssistantModelResolutionInput {\n identity: SurveyAssistantAuthorizedIdentity;\n request: Request;\n requestedModelId?: string;\n}\n\nexport type SurveyAssistantResolveModel = (\n input: SurveyAssistantModelResolutionInput,\n) =>\n | Promise<SurveyAssistantModelSelection | null | undefined>\n | SurveyAssistantModelSelection\n | null\n | undefined;\n\nexport class SurveyAssistantAuthorizationError extends Error {\n readonly status: number;\n\n constructor(message = \"The survey assistant request is not authorized.\", status = 403) {\n super(message);\n this.name = \"SurveyAssistantAuthorizationError\";\n this.status = status;\n }\n}\n\nexport interface SurveyAssistantTurnMetrics {\n durationMs?: number;\n snapshotBytes: number;\n toolCalls: number;\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n terminationReason?: SurveyAssistantTurnTerminationReason;\n}\n\nexport interface SurveyAssistantStreamErrorContext {\n resourceId: string;\n surveyId?: string;\n threadId: string;\n}\n\nexport interface SurveyAssistantChatHandlerOptions {\n mastra: Mastra | (() => Mastra | Promise<Mastra>);\n authorize: SurveyAssistantAuthorize;\n activeTools: readonly string[];\n agentId?: string;\n trustedCapabilities?: SurveyAssistantCapabilitySet;\n isEnabled?: (request: Request) => boolean | Promise<boolean>;\n getReadinessError?: (request: Request) => string | null | Promise<string | null>;\n firstResponseTimeoutMs?: number;\n idleTimeoutMs?: number;\n maxConcurrentRequests?: number;\n maxDurationMs?: number;\n maxSteps?: number;\n providerName?: string;\n providerOptions?: ProviderOptions;\n sendReasoning?: boolean;\n formatStreamError?: (error: unknown, context: SurveyAssistantStreamErrorContext) => string;\n onStreamError?: (error: unknown, context: SurveyAssistantStreamErrorContext) => void;\n onTurnMetrics?: (input: {\n identity: SurveyAssistantAuthorizedIdentity;\n metrics: SurveyAssistantTurnMetrics;\n provider?: string;\n turnId: string;\n }) => void;\n /** Optional overrides; omitted values use the safe package defaults. */\n requestLimits?: Partial<SurveyAssistantRequestLimits>;\n resolveModel?: SurveyAssistantResolveModel;\n threadDocuments?: SurveyAssistantThreadDocumentRepository;\n}\n\ntype SurveyAssistantChatParams = {\n messages?: unknown;\n snapshot?: unknown;\n previousSettledVersion?: unknown;\n previousApplyOutcome?: unknown;\n id?: unknown;\n resourceId?: unknown;\n modelId?: unknown;\n threadId?: unknown;\n surveyId?: unknown;\n trigger?: \"submit-message\" | \"regenerate-message\";\n} & Record<string, unknown>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst optionalRequestedId = (value: unknown) => {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= 240 ? normalized : undefined;\n};\n\nconst validateAuthorizedIdentity = (\n identity: SurveyAssistantAuthorizedIdentity,\n): SurveyAssistantAuthorizedIdentity => {\n if (\n !identity ||\n (identity.authority !== \"authenticated-host\" &&\n identity.authority !== \"experimental-client-request\") ||\n typeof identity.resourceId !== \"string\" ||\n identity.resourceId.trim().length === 0 ||\n identity.resourceId.length > 240 ||\n (identity.surveyId !== undefined && !optionalRequestedId(identity.surveyId)) ||\n typeof identity.threadId !== \"string\" ||\n identity.threadId.trim().length === 0 ||\n identity.threadId.length > 240\n ) {\n throw new SurveyAssistantAuthorizationError(\n \"The host returned an invalid survey assistant identity.\",\n 500,\n );\n }\n\n return {\n authority: identity.authority,\n resourceId: identity.resourceId.trim(),\n ...(identity.surveyId ? { surveyId: optionalRequestedId(identity.surveyId) } : {}),\n threadId: identity.threadId.trim(),\n };\n};\n\nconst validateModelSelection = (\n selection: SurveyAssistantModelSelection | null | undefined,\n): SurveyAssistantModelSelection | null => {\n if (!selection) return null;\n const id = optionalRequestedId(selection.id);\n const modelValue: unknown = selection.model;\n const stringModel = typeof modelValue === \"string\" ? optionalRequestedId(modelValue) : undefined;\n const objectModel = (() => {\n if (!isRecord(modelValue)) return undefined;\n const url = modelValue.url;\n const apiKey = modelValue.apiKey;\n const headers = modelValue.headers;\n if (\n (url !== undefined && typeof url !== \"string\") ||\n (apiKey !== undefined && typeof apiKey !== \"string\") ||\n (headers !== undefined &&\n (!isRecord(headers) || Object.values(headers).some((value) => typeof value !== \"string\")))\n ) {\n return undefined;\n }\n const shared = {\n ...(url === undefined ? {} : { url }),\n ...(apiKey === undefined ? {} : { apiKey }),\n ...(headers === undefined ? {} : { headers: headers as Record<string, string> }),\n };\n const compatibleId = optionalRequestedId(modelValue.id);\n if (compatibleId) {\n return { id: compatibleId, ...shared } as SurveyAssistantModelSelection[\"model\"];\n }\n const providerId = optionalRequestedId(modelValue.providerId);\n const modelId = optionalRequestedId(modelValue.modelId);\n if (providerId && modelId) {\n return {\n providerId,\n modelId,\n ...shared,\n } as SurveyAssistantModelSelection[\"model\"];\n }\n return undefined;\n })();\n return id && (stringModel || objectModel) ? { id, model: stringModel ?? objectModel! } : null;\n};\n\nconst readNumber = (value: unknown): number | undefined =>\n typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n\nconst recordTurnStreamPart = (metrics: SurveyAssistantTurnMetrics, part: unknown) => {\n if (!isRecord(part)) return;\n if (part.type === \"tool-call\") metrics.toolCalls += 1;\n if (part.type !== \"finish\") return;\n\n const payload = isRecord(part.payload) ? part.payload : undefined;\n const output = isRecord(payload?.output) ? payload.output : undefined;\n const usage = isRecord(output?.usage) ? output.usage : undefined;\n if (!usage) return;\n\n metrics.inputTokens = readNumber(usage.inputTokens);\n metrics.outputTokens = readNumber(usage.outputTokens);\n metrics.totalTokens = readNumber(usage.totalTokens);\n metrics.reasoningTokens = readNumber(usage.reasoningTokens);\n metrics.cachedInputTokens = readNumber(usage.cachedInputTokens);\n};\n\nconst unwrapStreamError = (error: unknown) => {\n if (isRecord(error) && error.error !== undefined) return error.error;\n return error;\n};\n\nconst describeErrorLevel = (value: unknown): Record<string, unknown> => {\n if (value instanceof Error) {\n const properties = Object.fromEntries(\n Object.getOwnPropertyNames(value)\n .filter((key) => key !== \"stack\")\n .map((key) => [key, (value as unknown as Record<string, unknown>)[key]]),\n );\n return { name: value.name, message: value.message, stack: value.stack, ...properties };\n }\n\n if (isRecord(value)) {\n return {\n constructorName: value.constructor?.name,\n ...Object.fromEntries(Object.getOwnPropertyNames(value).map((key) => [key, value[key]])),\n };\n }\n\n return { value };\n};\n\nexport const describeSurveyAssistantStreamError = (error: unknown) => {\n const levels: Record<string, unknown>[] = [];\n let current: unknown = unwrapStreamError(error);\n\n for (\n let depth = 0;\n depth < MAX_ERROR_CAUSE_DEPTH && current !== undefined && current !== null;\n depth += 1\n ) {\n const level = describeErrorLevel(current);\n levels.push(level);\n current = level.cause;\n }\n\n return levels.length === 1 ? levels[0] : { levels };\n};\n\nconst clampUserErrorMessage = (message: string) => {\n const normalized = message.replace(/\\s+/g, \" \").trim();\n return normalized.length <= MAX_USER_ERROR_MESSAGE_LENGTH\n ? normalized\n : `${normalized.slice(0, MAX_USER_ERROR_MESSAGE_LENGTH - 1)}…`;\n};\n\nconst getProviderModelName = (message: string) =>\n message.match(/\\bmodel\\s+[`'\"]([^`'\"]+)[`'\"]/i)?.[1]?.trim();\n\nconst classifyStreamError = (message: string, statusCode?: number): SurveyAssistantErrorCode => {\n if (statusCode === 401 || statusCode === 403) return \"authorization_failed\";\n if (statusCode === 429) return \"rate_limited\";\n if (\n /\\bmodel\\b[\\s\\S]{0,160}\\b(?:limited preview|not available)\\b/i.test(message) ||\n /\\blimited preview\\b[\\s\\S]{0,160}\\bmodel\\b/i.test(message)\n ) {\n return \"model_unavailable\";\n }\n if (/\\b(?:rate limit|too many requests|request limit)\\b/i.test(message)) {\n return \"rate_limited\";\n }\n if (\n /\\b(?:invalid api key|incorrect api key|authentication|unauthorized|forbidden)\\b/i.test(message)\n ) {\n return \"authorization_failed\";\n }\n if (\n /\\b(?:attachment|document|file)\\b[\\s\\S]{0,120}\\b(?:missing|unavailable|not found|failed)\\b/i.test(\n message,\n )\n ) {\n return \"attachment_unavailable\";\n }\n return \"request_failed\";\n};\n\nconst formatKnownProviderError = (message: string) => {\n const normalized = clampUserErrorMessage(message);\n if (\n /\\bmodel\\b[\\s\\S]{0,160}\\b(?:limited preview|not available)\\b/i.test(normalized) ||\n /\\blimited preview\\b[\\s\\S]{0,160}\\bmodel\\b/i.test(normalized)\n ) {\n const modelName = getProviderModelName(normalized);\n return `The configured model${modelName ? ` \\`${modelName}\\`` : \"\"} is not available on this account.`;\n }\n if (/\\b(?:rate limit|too many requests|request limit)\\b/i.test(normalized)) {\n return \"The AI provider is temporarily limiting requests.\";\n }\n if (\n /\\b(?:invalid api key|incorrect api key|authentication|unauthorized|forbidden)\\b/i.test(\n normalized,\n )\n ) {\n return \"The AI provider rejected the assistant credentials.\";\n }\n return \"The AI provider could not complete the request.\";\n};\n\nconst parseProviderResponseBodyMessage = (responseBody: unknown) => {\n if (typeof responseBody !== \"string\" || responseBody.trim().length === 0) return undefined;\n try {\n const parsed = JSON.parse(responseBody) as unknown;\n if (isRecord(parsed) && isRecord(parsed.error) && typeof parsed.error.message === \"string\") {\n return parsed.error.message;\n }\n } catch {\n return responseBody;\n }\n return responseBody;\n};\n\nconst extractUserErrorMessageFromLevel = (level: Record<string, unknown>) => {\n if (\n isRecord(level.data) &&\n isRecord(level.data.error) &&\n typeof level.data.error.message === \"string\"\n ) {\n return level.data.error.message;\n }\n return (\n parseProviderResponseBodyMessage(level.responseBody) ??\n (typeof level.message === \"string\" ? level.message : undefined)\n );\n};\n\nexport const formatSurveyAssistantStreamError = (error: unknown) => {\n const describedError = describeSurveyAssistantStreamError(error);\n const levels = Array.isArray(describedError.levels) ? describedError.levels : [describedError];\n const messageLevel = levels.find(\n (level): level is Record<string, unknown> =>\n isRecord(level) && Boolean(extractUserErrorMessageFromLevel(level)),\n );\n const statusLevel = levels.find(\n (level): level is Record<string, unknown> => isRecord(level) && level.statusCode !== undefined,\n );\n const statusCode = Number(statusLevel?.statusCode);\n const detail = messageLevel ? extractUserErrorMessageFromLevel(messageLevel) : undefined;\n const formattedDetail = detail ? formatKnownProviderError(detail) : undefined;\n return serializeSurveyAssistantError({\n code: classifyStreamError(\n formattedDetail ?? \"\",\n Number.isFinite(statusCode) ? statusCode : undefined,\n ),\n ...(formattedDetail ? { detail: formattedDetail } : {}),\n });\n};\n\nconst requestErrorResponse = (error: unknown, fallback: string) => {\n const requestError =\n error instanceof SurveyAssistantRequestError\n ? error\n : new SurveyAssistantRequestError(fallback);\n return Response.json(\n { code: \"request_failed\", error: requestError.message },\n { status: requestError.status },\n );\n};\n\nexport const createSurveyAssistantChatHandler = (options: SurveyAssistantChatHandlerOptions) => {\n const requestLimits: SurveyAssistantRequestLimits = {\n ...SURVEY_ASSISTANT_DEFAULT_REQUEST_LIMITS,\n ...options.requestLimits,\n };\n for (const [name, value] of Object.entries(requestLimits)) {\n if (\n name !== \"acceptedAttachmentTypes\" &&\n (!Number.isSafeInteger(value) || (value as number) <= 0)\n ) {\n throw new Error(`Survey assistant request limit \"${name}\" must be a positive integer.`);\n }\n }\n if (typeof requestLimits.acceptedAttachmentTypes?.has !== \"function\") {\n throw new Error(\"Survey assistant accepted attachment types must be a set.\");\n }\n const maxConcurrentRequests =\n Number.isInteger(options.maxConcurrentRequests) && (options.maxConcurrentRequests ?? 0) > 0\n ? options.maxConcurrentRequests!\n : DEFAULT_MAX_CONCURRENT_REQUESTS;\n const firstResponseTimeoutMs =\n Number.isFinite(options.firstResponseTimeoutMs) && (options.firstResponseTimeoutMs ?? 0) > 0\n ? options.firstResponseTimeoutMs!\n : DEFAULT_FIRST_RESPONSE_TIMEOUT_MS;\n const idleTimeoutMs =\n Number.isFinite(options.idleTimeoutMs) && (options.idleTimeoutMs ?? 0) > 0\n ? options.idleTimeoutMs!\n : DEFAULT_IDLE_TIMEOUT_MS;\n const maxSteps =\n Number.isInteger(options.maxSteps) && (options.maxSteps ?? 0) > 0\n ? options.maxSteps!\n : DEFAULT_MAX_STEPS;\n const maxDurationMs =\n Number.isFinite(options.maxDurationMs) && (options.maxDurationMs ?? 0) > 0\n ? options.maxDurationMs!\n : DEFAULT_MAX_DURATION_MS;\n let activeRequestCount = 0;\n\n const acquireRequestSlot = () => {\n if (activeRequestCount >= maxConcurrentRequests) return null;\n activeRequestCount += 1;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n activeRequestCount = Math.max(0, activeRequestCount - 1);\n };\n };\n\n return async (request: Request): Promise<Response> => {\n if (options.isEnabled && !(await options.isEnabled(request))) {\n return Response.json(\n { code: \"authorization_failed\", error: \"Survey assistant is disabled.\" },\n { status: 404 },\n );\n }\n\n let rawParams: unknown;\n try {\n rawParams = await readSurveyAssistantRequestJson(request, requestLimits.maxRequestBytes);\n } catch (error) {\n return requestErrorResponse(error, \"The survey assistant request could not be read.\");\n }\n\n const params = isRecord(rawParams)\n ? (rawParams as SurveyAssistantChatParams)\n : ({} satisfies SurveyAssistantChatParams);\n\n let identity: SurveyAssistantAuthorizedIdentity;\n try {\n identity = validateAuthorizedIdentity(\n await options.authorize({\n request,\n requestedResourceId: optionalRequestedId(params.resourceId),\n requestedThreadId: optionalRequestedId(params.threadId ?? params.id),\n requestedSurveyId: optionalRequestedId(params.surveyId),\n }),\n );\n } catch (error) {\n const authorizationError =\n error instanceof SurveyAssistantAuthorizationError\n ? error\n : new SurveyAssistantAuthorizationError();\n return Response.json(\n { code: \"authorization_failed\", error: authorizationError.message },\n { status: authorizationError.status },\n );\n }\n\n let messages: UIMessage[];\n try {\n messages = validateSurveyAssistantMessages(params.messages, requestLimits);\n } catch (error) {\n return requestErrorResponse(error, \"The survey assistant messages are invalid.\");\n }\n\n let modelSelection: SurveyAssistantModelSelection | undefined;\n if (options.resolveModel) {\n const requestedModelId = optionalRequestedId(params.modelId);\n if (params.modelId !== undefined && !requestedModelId) {\n return Response.json(\n { code: \"model_unavailable\", error: \"Invalid survey assistant model selection.\" },\n { status: 400 },\n );\n }\n\n try {\n modelSelection =\n validateModelSelection(\n await options.resolveModel({ identity, request, requestedModelId }),\n ) ?? undefined;\n } catch (error) {\n options.onStreamError?.(error, {\n resourceId: identity.resourceId,\n surveyId: identity.surveyId,\n threadId: identity.threadId,\n });\n return Response.json(\n {\n code: \"model_unavailable\",\n error: \"The survey assistant model catalog is unavailable.\",\n },\n { status: 503 },\n );\n }\n if (!modelSelection) {\n return Response.json(\n {\n code: \"model_unavailable\",\n error: \"The selected survey assistant model is not available.\",\n },\n { status: 400 },\n );\n }\n }\n\n let snapshot: SurveyDocumentSnapshot | null;\n let previousSettledVersion;\n let previousApplyOutcome;\n try {\n snapshot = parseSurveyAssistantSnapshot(params.snapshot);\n previousSettledVersion = parseSurveyAssistantPreviousSettledVersion(\n params.previousSettledVersion,\n );\n previousApplyOutcome = parseSurveyAssistantPreviousApplyOutcome(params.previousApplyOutcome);\n } catch {\n return Response.json(\n { code: \"request_failed\", error: \"Invalid survey assistant document context.\" },\n { status: 400 },\n );\n }\n\n const readinessError = await options.getReadinessError?.(request);\n if (readinessError) {\n return Response.json({ code: \"request_failed\", error: readinessError }, { status: 503 });\n }\n\n const releaseRequestSlot = acquireRequestSlot();\n if (!releaseRequestSlot) {\n return Response.json(\n {\n code: \"rate_limited\",\n error: \"The survey assistant is handling too many requests. Try again shortly.\",\n },\n { status: 429 },\n );\n }\n\n const turnDraft = new TurnSurveyDraft();\n let requestContext;\n try {\n let attachmentAccess: SurveyAssistantAttachmentAccess | undefined;\n let modelAttachments: SurveyAssistantModelAttachment[] = [];\n if (options.threadDocuments) {\n const repository = options.threadDocuments;\n const registered = await registerSurveyAssistantThreadAttachments({\n messages,\n repository,\n resourceId: identity.resourceId,\n threadId: identity.threadId,\n });\n const manifest = await repository.list({\n resourceId: identity.resourceId,\n threadId: identity.threadId,\n });\n modelAttachments = await loadSurveyAssistantDocuments({\n documents: registered,\n repository,\n resourceId: identity.resourceId,\n threadId: identity.threadId,\n });\n messages = replaceCurrentSurveyAssistantAttachmentsWithReferences({\n documents: registered,\n messages,\n });\n messages = removeHistoricalSurveyAssistantAttachments(messages);\n const registeredIds = new Set(registered.map((document) => document.id));\n const replayableDocuments = getSurveyAssistantReplayableDocuments(manifest, registeredIds);\n const documents = [...registered, ...replayableDocuments];\n if (documents.length > 0) {\n attachmentAccess = {\n documents,\n currentDocumentIds: registered.map((document) => document.id),\n selectedAttachments: [],\n load: (documentIds) =>\n loadSurveyAssistantDocuments({\n documents: documents.filter((document) => documentIds.includes(document.id)),\n repository,\n resourceId: identity.resourceId,\n threadId: identity.threadId,\n }),\n };\n }\n }\n requestContext = buildSurveyAssistantRequestContext({\n turnDraft,\n identity,\n snapshot,\n previousSettledVersion,\n previousApplyOutcome,\n trustedCapabilities: options.trustedCapabilities,\n attachmentAccess,\n modelAttachments,\n modelSelection,\n });\n } catch (error) {\n releaseRequestSlot();\n if (error instanceof SurveyAssistantRequestError) {\n return requestErrorResponse(error, \"The thread attachments could not be prepared.\");\n }\n if (error instanceof SurveyAssistantCapabilityMismatchError) {\n return Response.json({ error: error.message, code: error.code }, { status: 409 });\n }\n options.onStreamError?.(error, {\n resourceId: identity.resourceId,\n surveyId: identity.surveyId,\n threadId: identity.threadId,\n });\n return Response.json(\n {\n code: \"attachment_unavailable\",\n error: \"The survey assistant could not prepare the thread's reference documents.\",\n },\n { status: 503 },\n );\n }\n\n const metrics: SurveyAssistantTurnMetrics = {\n snapshotBytes: snapshot ? new TextEncoder().encode(JSON.stringify(snapshot)).byteLength : 0,\n toolCalls: 0,\n };\n const streamErrorContext = {\n resourceId: identity.resourceId,\n surveyId: identity.surveyId,\n threadId: identity.threadId,\n };\n const executionStartedAt = Date.now();\n const executionTimeout = createSurveyAssistantExecutionTimeout({\n firstResponseTimeoutMs,\n idleTimeoutMs,\n maxDurationMs,\n requestSignal: request.signal,\n });\n const executionSignal = executionTimeout.signal;\n const finalizeExecutionTurn = (\n status: \"completed\" | \"failed\" | \"aborted\",\n terminationReason?: SurveyAssistantTurnTerminationReason,\n ) => {\n const completedAt = Date.now();\n return turnDraft.finalize(status, new Date(completedAt).toISOString(), {\n startedAt: new Date(executionStartedAt).toISOString(),\n durationMs: Math.max(0, completedAt - executionStartedAt),\n ...(terminationReason ? { terminationReason } : {}),\n });\n };\n const handleStreamError = (error: unknown) => {\n options.onStreamError?.(error, streamErrorContext);\n return (\n options.formatStreamError?.(error, streamErrorContext) ??\n formatSurveyAssistantStreamError(error)\n );\n };\n\n let stream: ReadableStream<UIMessageChunk>;\n try {\n const mastra = typeof options.mastra === \"function\" ? await options.mastra() : options.mastra;\n stream = (await handleChatStream({\n mastra,\n agentId: options.agentId ?? SURVEY_ASSISTANT_AGENT_ID,\n version: \"v6\",\n params: {\n messages,\n ...(params.trigger ? { trigger: params.trigger } : {}),\n requestContext,\n runId: turnDraft.turnId,\n abortSignal: executionSignal,\n onAbort: () => {\n finalizeExecutionTurn(\n executionTimeout.timeoutKind ? \"failed\" : \"aborted\",\n executionTimeout.timeoutKind\n ? getTimeoutTerminationReason(executionTimeout.timeoutKind)\n : \"client-abort\",\n );\n },\n onError: () => {\n finalizeExecutionTurn(\"failed\", \"provider-error\");\n },\n memory: {\n thread: identity.threadId,\n resource: identity.resourceId,\n },\n },\n defaultOptions: {\n activeTools: [...options.activeTools],\n maxSteps,\n ...(options.providerOptions ? { providerOptions: options.providerOptions } : {}),\n },\n sendReasoning: options.sendReasoning ?? true,\n messageMetadata: ({ part }: { part: unknown }) => {\n recordTurnStreamPart(metrics, part);\n return undefined;\n },\n onError: (error: unknown) => {\n finalizeExecutionTurn(\"failed\", \"provider-error\");\n return handleStreamError(error);\n },\n } as never)) as ReadableStream<UIMessageChunk>;\n } catch (error) {\n finalizeExecutionTurn(\n executionTimeout.timeoutKind ? \"failed\" : executionSignal.aborted ? \"aborted\" : \"failed\",\n executionTimeout.timeoutKind\n ? getTimeoutTerminationReason(executionTimeout.timeoutKind)\n : executionSignal.aborted\n ? \"client-abort\"\n : \"provider-error\",\n );\n executionTimeout.dispose();\n releaseRequestSlot();\n return Response.json(\n {\n error: executionTimeout.timeoutKind\n ? getSurveyAssistantExecutionTimeoutMessage(executionTimeout.timeoutKind)\n : handleStreamError(error),\n },\n { status: 503 },\n );\n }\n\n const turnStream = createSurveyAssistantTurnStream({\n stream,\n turnDraft,\n signal: executionSignal,\n getAbortErrorText: () =>\n executionTimeout.timeoutKind\n ? getSurveyAssistantExecutionTimeoutMessage(executionTimeout.timeoutKind)\n : undefined,\n getAbortTerminationReason: () =>\n executionTimeout.timeoutKind\n ? getTimeoutTerminationReason(executionTimeout.timeoutKind)\n : request.signal.aborted\n ? \"client-abort\"\n : undefined,\n onActivity: executionTimeout.recordActivity,\n onUnexpectedError: handleStreamError,\n onSettled: () => {\n executionTimeout.dispose();\n releaseRequestSlot();\n metrics.durationMs = Date.now() - executionStartedAt;\n metrics.terminationReason = turnDraft.final?.terminationReason;\n try {\n options.onTurnMetrics?.({\n identity,\n metrics,\n provider: options.providerName,\n turnId: turnDraft.turnId,\n });\n } catch (error) {\n try {\n options.onStreamError?.(error, streamErrorContext);\n } catch {\n // Host observability hooks must not break an already-settled stream.\n }\n }\n },\n turnStartedAt: executionStartedAt,\n });\n\n return createUIMessageStreamResponse({ stream: turnStream });\n };\n};\n","import {\n createSurveyAssistantThreadInputSchema,\n updateSurveyAssistantThreadInputSchema,\n type SurveyAssistantThread,\n} from \"../protocol\";\nimport { readSurveyAssistantRequestJson, SurveyAssistantRequestError } from \"./request-guardrails\";\n\nconst DEFAULT_TITLE = \"New chat\";\nconst MAX_THREAD_MUTATION_BYTES = 16 * 1024;\nconst MANUAL_TITLE_METADATA_KEY = \"surveyAssistant.manualTitle\";\nconst AUTOMATIC_TITLE_METADATA_KEY = \"surveyAssistant.automaticTitle\";\n\nexport interface SurveyAssistantThreadIdentity {\n resourceId: string;\n metadata: Record<string, string>;\n}\n\nexport interface CreateSurveyAssistantThreadHandlersOptions {\n authorize(\n request: Request,\n ): SurveyAssistantThreadIdentity | Promise<SurveyAssistantThreadIdentity>;\n repository: SurveyAssistantThreadRepository;\n}\n\nexport interface SurveyAssistantStoredThread {\n id: string;\n title?: string;\n resourceId: string;\n createdAt: Date;\n updatedAt: Date;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SurveyAssistantThreadRepository {\n create(input: {\n resourceId: string;\n title: string;\n metadata: Record<string, unknown>;\n }): Promise<SurveyAssistantStoredThread>;\n get(threadId: string): Promise<SurveyAssistantStoredThread | null>;\n list(\n resourceId: string,\n metadata: Record<string, string>,\n ): Promise<SurveyAssistantStoredThread[]>;\n readMessages(threadId: string, resourceId: string): Promise<unknown[]>;\n delete(threadId: string): Promise<void>;\n update(input: {\n id: string;\n title: string;\n metadata: Record<string, unknown>;\n }): Promise<SurveyAssistantStoredThread>;\n}\n\nconst getMetadataString = (metadata: Record<string, unknown> | undefined, key: string) => {\n const value = metadata?.[key];\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n};\n\nconst getRawTitle = (thread: SurveyAssistantStoredThread) => thread.title?.trim() || DEFAULT_TITLE;\n\nconst getAutomaticTitle = (thread: SurveyAssistantStoredThread, manualTitle: string): string => {\n const rawTitle = thread.title?.trim();\n if (rawTitle && rawTitle !== manualTitle) return rawTitle;\n return getMetadataString(thread.metadata, AUTOMATIC_TITLE_METADATA_KEY) ?? DEFAULT_TITLE;\n};\n\nconst asThread = (thread: SurveyAssistantStoredThread): SurveyAssistantThread => {\n const manualTitle = getMetadataString(thread.metadata, MANUAL_TITLE_METADATA_KEY);\n\n return {\n id: thread.id,\n title: manualTitle ?? getRawTitle(thread),\n titleMode: manualTitle ? \"manual\" : \"automatic\",\n createdAt: thread.createdAt.toISOString(),\n updatedAt: thread.updatedAt.toISOString(),\n };\n};\n\nconst json = (body: unknown, status = 200) => Response.json(body, { status });\n\nconst errorResponse = (error: unknown) => {\n const status =\n typeof error === \"object\" &&\n error !== null &&\n \"status\" in error &&\n typeof error.status === \"number\"\n ? error.status\n : error instanceof SurveyAssistantRequestError ||\n error instanceof SyntaxError ||\n (error instanceof Error && error.name === \"ZodError\")\n ? 400\n : 500;\n const message =\n error instanceof SurveyAssistantRequestError\n ? error.message\n : status === 401 || status === 403 || status === 404\n ? status === 404\n ? \"Chat not found.\"\n : \"The chat request is not authorized.\"\n : status >= 500\n ? \"The chat request could not be completed.\"\n : \"The chat request is invalid.\";\n return json(\n {\n code:\n status === 401 || status === 403 || status === 404\n ? \"authorization_failed\"\n : \"request_failed\",\n error: message,\n },\n status,\n );\n};\n\nconst ownsThread = (thread: SurveyAssistantStoredThread, identity: SurveyAssistantThreadIdentity) =>\n thread.resourceId === identity.resourceId &&\n Object.entries(identity.metadata).every(([key, value]) => thread.metadata?.[key] === value);\n\nconst getOwnedThread = async (\n repository: SurveyAssistantThreadRepository,\n identity: SurveyAssistantThreadIdentity,\n threadId: string,\n) => {\n const thread = await repository.get(threadId);\n return thread && ownsThread(thread, identity) ? thread : null;\n};\n\nexport const createSurveyAssistantThreadHandlers = ({\n authorize,\n repository,\n}: CreateSurveyAssistantThreadHandlersOptions) => {\n const list = async (request: Request) => {\n try {\n const identity = await authorize(request);\n const storedThreads = await repository.list(identity.resourceId, identity.metadata);\n const threads = storedThreads\n .filter(\n (thread) =>\n ownsThread(thread, identity) && typeof thread.metadata?.archivedAt !== \"string\",\n )\n .map(asThread);\n return json({ threads });\n } catch (error) {\n return errorResponse(error);\n }\n };\n\n const create = async (request: Request) => {\n try {\n const [identity, input] = await Promise.all([\n authorize(request),\n readSurveyAssistantRequestJson(request, MAX_THREAD_MUTATION_BYTES),\n ]);\n const parsed = createSurveyAssistantThreadInputSchema.parse(input);\n const metadata = { ...identity.metadata };\n if (parsed.title) {\n metadata[MANUAL_TITLE_METADATA_KEY] = parsed.title;\n metadata[AUTOMATIC_TITLE_METADATA_KEY] = DEFAULT_TITLE;\n }\n const thread = await repository.create({\n resourceId: identity.resourceId,\n title: parsed.title ?? DEFAULT_TITLE,\n metadata,\n });\n return json({ thread: asThread(thread) }, 201);\n } catch (error) {\n return errorResponse(error);\n }\n };\n\n const read = async (request: Request, threadId: string) => {\n try {\n const identity = await authorize(request);\n const thread = await getOwnedThread(repository, identity, threadId);\n if (!thread || typeof thread.metadata?.archivedAt === \"string\") {\n return json({ error: \"Chat not found.\" }, 404);\n }\n return json({\n thread: asThread(thread),\n messages: await repository.readMessages(threadId, identity.resourceId),\n });\n } catch (error) {\n return errorResponse(error);\n }\n };\n\n const update = async (request: Request, threadId: string) => {\n try {\n const [identity, input] = await Promise.all([\n authorize(request),\n readSurveyAssistantRequestJson(request, MAX_THREAD_MUTATION_BYTES),\n ]);\n const thread = await getOwnedThread(repository, identity, threadId);\n if (!thread || typeof thread.metadata?.archivedAt === \"string\") {\n return json({ error: \"Chat not found.\" }, 404);\n }\n const parsed = updateSurveyAssistantThreadInputSchema.parse(input);\n const metadata = { ...(thread.metadata ?? identity.metadata) };\n let title: string;\n\n if (parsed.mode === \"automatic\") {\n const manualTitle = getMetadataString(metadata, MANUAL_TITLE_METADATA_KEY);\n title =\n parsed.title ??\n (manualTitle ? getAutomaticTitle(thread, manualTitle) : getRawTitle(thread));\n metadata[MANUAL_TITLE_METADATA_KEY] = null;\n metadata[AUTOMATIC_TITLE_METADATA_KEY] = null;\n } else {\n const previousManualTitle = getMetadataString(metadata, MANUAL_TITLE_METADATA_KEY);\n const automaticTitle = previousManualTitle\n ? getAutomaticTitle(thread, previousManualTitle)\n : getRawTitle(thread);\n title = parsed.title;\n metadata[MANUAL_TITLE_METADATA_KEY] = title;\n metadata[AUTOMATIC_TITLE_METADATA_KEY] = automaticTitle;\n }\n\n const updated = await repository.update({\n id: thread.id,\n title,\n metadata,\n });\n return json({ thread: asThread(updated) });\n } catch (error) {\n return errorResponse(error);\n }\n };\n\n const deleteThread = async (request: Request, threadId: string) => {\n try {\n const identity = await authorize(request);\n const thread = await getOwnedThread(repository, identity, threadId);\n if (!thread) return json({ error: \"Chat not found.\" }, 404);\n await repository.delete(thread.id);\n return new Response(null, { status: 204 });\n } catch (error) {\n return errorResponse(error);\n }\n };\n\n return { create, delete: deleteThread, list, read, update };\n};\n","import { toAISdkMessages } from \"@mastra/ai-sdk/ui\";\nimport type { MastraMemory } from \"@mastra/core/memory\";\nimport type { SurveyAssistantThreadDocumentRepository } from \"./thread-documents\";\nimport type { SurveyAssistantThreadRepository } from \"./thread-handlers\";\n\ntype ThreadMemory = Pick<\n MastraMemory,\n \"createThread\" | \"deleteThread\" | \"getThreadById\" | \"listThreads\" | \"recall\" | \"updateThread\"\n>;\n\nexport interface CreateMastraMemoryThreadRepositoryOptions {\n getMemory(): ThreadMemory | Promise<ThreadMemory>;\n /** Maximum recent messages returned when hydrating a transcript. */\n maxMessagesPerTranscript?: number;\n /** Maximum recent threads returned by the history endpoint. */\n maxThreadsPerList?: number;\n threadDocuments?: SurveyAssistantThreadDocumentRepository;\n}\n\nexport const createMastraMemoryThreadRepository = ({\n getMemory,\n maxMessagesPerTranscript = 1_000,\n maxThreadsPerList = 100,\n threadDocuments,\n}: CreateMastraMemoryThreadRepositoryOptions): SurveyAssistantThreadRepository => ({\n async create({ metadata, resourceId, title }) {\n return (await getMemory()).createThread({ metadata, resourceId, title, saveThread: true });\n },\n async get(threadId) {\n return (await getMemory()).getThreadById({ threadId });\n },\n async list(resourceId, metadata) {\n const result = await (\n await getMemory()\n ).listThreads({\n filter: { metadata, resourceId },\n orderBy: { field: \"updatedAt\", direction: \"DESC\" },\n perPage: Math.max(1, Math.min(1_000, maxThreadsPerList)),\n });\n return result.threads;\n },\n async readMessages(threadId, resourceId) {\n const result = await (\n await getMemory()\n ).recall({\n threadId,\n resourceId,\n perPage: Math.max(1, Math.min(5_000, maxMessagesPerTranscript)),\n orderBy: { field: \"createdAt\", direction: \"DESC\" },\n });\n return toAISdkMessages([...result.messages].reverse(), { version: \"v6\" });\n },\n async delete(threadId) {\n const memory = await getMemory();\n const thread = await memory.getThreadById({ threadId });\n if (thread && threadDocuments) {\n await threadDocuments.deleteThread({ resourceId: thread.resourceId, threadId });\n }\n await memory.deleteThread(threadId);\n },\n async update({ id, metadata, title }) {\n return (await getMemory()).updateThread({ id, metadata, title });\n },\n});\n"],"mappings":"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"}