@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
@@ -27,7 +27,7 @@ Use this reference when the user asks to implement, recreate, convert, import, o
27
27
  ## Item Mapping
28
28
 
29
29
  - Map supported item types directly. Use `choiceItem` for single choice, multiple choice, and scale-like questions until a dedicated scale item exists.
30
- - For scale questions, create an ordered `choiceItem` with stable option ids/keys and labels that preserve the endpoints and intermediate labels. Include the scale instruction in `subtitle` or `topContent` when it is not part of the actual question.
30
+ - For scale questions, create an ordered `choiceItem` with stable option IDs/codes and labels that preserve the endpoints and intermediate labels. Include the scale instruction in `subtitle` or `topContent` when it is not part of the actual question.
31
31
  - Use a simple `formItem` preset for a single text, long-text, number, slider, dropdown, date, or switch response. Use custom form mode for grouped personal data, tables, repeated inputs, contact details, or unsupported compound controls.
32
32
  - Prefer the supported semantic field type for the respondent value instead of copying the paper
33
33
  form's box layout. Use one `datepicker` with mode `year-month-day` for an ordinary full calendar
@@ -36,9 +36,9 @@ Use this reference when the user asks to implement, recreate, convert, import, o
36
36
  - Use choice option embedded forms for choices that include an open field, such as "Other, specify", "Yes, explain", or an option-specific quantity/date/text input.
37
37
  - Preserve option-level parenthetical instructions, side notes, and footnote markers. If the current choice option UI has no separate option-description surface, fold short option notes into the visible option label, for example `Uitgenodigde persoon zelf (zie hiervoor de naam op de brief en/of geboortedatum op de voorkant van de vragenlijst)`, and keep markers such as `Iemand anders*`.
38
38
  - For sentence-completion options with an embedded input, put the completion cue on the embedded field label, not twice. Source text like `Iemand anders*, namelijk ____`, `Andere bedrijfstak, namelijk ____`, or `Other, please specify ____` should become option label `Iemand anders*` / `Andere bedrijfstak` / `Other` and embedded field label `Namelijk` / `Please specify`.
39
- - Use info items for non-interactive section introductions, explanations, consent/instruction text, and visible page/section headings. Keep a simple one-paragraph info item as plainText. Use richText only when the source requires headings, lists, links, separators, or meaningful emphasis.
39
+ - Use info items for non-interactive section introductions, explanations, instruction text, and visible page/section headings. Use a consent item when the participant must explicitly agree or decline, with the full information in `consentBody`. Keep simple paragraphs as plainText; use richText for headings, lists, links, separators, or meaningful emphasis.
40
40
  - Preserve major chapters/sections as survey structure. If page boundaries matter, use available page-break structure and/or a heading info item so respondents see the section break.
41
- - Include respondent-facing "before you begin", "how to complete this survey", consent, eligibility, safety, and contact/help sections as info items when still relevant digitally. Rewrite or omit paper-only return/postage instructions unless the user wants a literal reproduction.
41
+ - Include respondent-facing "before you begin", "how to complete this survey", eligibility, safety, and contact/help sections as info items when still relevant digitally. Preserve consent information and any requested decision using the appropriate info or consent item. Rewrite or omit paper-only return/postage instructions unless the user wants a literal reproduction.
42
42
 
43
43
  ## Layout And Grouping
44
44
 
@@ -57,6 +57,7 @@ Use this reference when the user asks to implement, recreate, convert, import, o
57
57
 
58
58
  - Rephrase only enough to make the digital survey clear and grammatically coherent. Preserve measurement meaning, recall periods, answer scales, and eligibility wording.
59
59
  - Split source text into the right visible content keys: concise question in `title`; instructions like "multiple answers possible" or recall-period guidance in `subtitle` or `topContent`; explanations after the control in `bottomContent`; non-question prose in info item `content`.
60
+ - For consent, put the document's main heading in `title`, a separate brief introduction or reading instruction in `subtitle` when needed, and the substantive document text in `consentBody`. Consent inherits those question fields by default. Use `consentTitle` only for a distinct consent heading, and `subtitleMode=custom` with `consentSubtitle` for a distinct consent introduction (`none` omits it from the consent). Avoid duplicating the main heading in the body, while retaining meaningful section headings and the supplied terms. Do not replace the document with a summary or an instruction to read content that has not been included; honor an explicit request for verbatim reproduction.
60
61
  - Use plainText for ordinary unformatted prose. Use richText, not plainText, only when info item content has headings, subheadings, boxed sections, bullet/list structure, examples, emphasized phrases, separators, footnotes, URLs, email links, or mixed inline formatting. Preserve the hierarchy with heading blocks, paragraph blocks, bullet lists, info boxes, or separators as supported.
61
62
  - Preserve meaningful inline source formatting, not only block layout. A URL or email address that is intended as a destination must be a richText `link` node with a canonical `href`; do not rely on automatic link detection. If source text emphasizes or highlights individual words in a question title, subtitle, option, or info text, author that content key as richText with styled inline runs instead of flattening it to plainText. Use emphasis only where it carries source meaning or scanning value.
62
63
  - For source-import surfaces documented as rendering rich text, prefer the compact `richTextBlocks` shorthand; `survey_change` normalizes it to strict richText. Do not infer formatting support merely because a typed field accepts structured content. Load `rich-text-content` for supported surfaces, compact and canonical nodes, and examples. Invalid or unknown nodes are rejected rather than silently omitted.
@@ -6,8 +6,12 @@ A survey JSON object has this shape:
6
6
 
7
7
  ```json
8
8
  {
9
+ "schemaVersion": 2,
9
10
  "$schema": "https://github.com/case-framework/case-survey-toolkit/packages/survey-core/schemas/survey-schema.json",
10
- "maxItemsPerPage": { "large": 1, "small": 1 },
11
+ "maxItemsPerPage": {
12
+ "large": 1,
13
+ "small": 1
14
+ },
11
15
  "surveyItems": [],
12
16
  "assets": {},
13
17
  "metadata": {},
@@ -19,6 +23,7 @@ A survey JSON object has this shape:
19
23
  Required fields:
20
24
 
21
25
  - `$schema`: keep the current schema string; never remove or edit it.
26
+ - `schemaVersion`: exactly `2`; never remove or edit it.
22
27
  - `surveyItems`: array of raw survey items.
23
28
 
24
29
  Optional fields:
@@ -36,15 +41,18 @@ Minimal item shape:
36
41
  ```json
37
42
  {
38
43
  "id": "stable-unique-id",
39
- "key": "coding_key",
40
- "itemType": "choiceItem"
44
+ "itemType": "choiceItem",
45
+ "config": {
46
+ "variableName": "coding_key"
47
+ }
41
48
  }
42
49
  ```
43
50
 
44
51
  Conventions:
45
52
 
46
53
  - `id` is globally unique and is the durable reference used by groups, translations, response slots, expressions, and patches.
47
- - `key` is the coding key shown in fullKey paths. Sibling keys must be unique and use letters, numbers, underscores, or hyphens.
54
+ - Items have no `key`. Inspection resolves `editorName` and `breadcrumb` for discovery; both may be duplicated and neither is an identity. Mutations take exact item IDs.
55
+ - Response slots have separate persistent IDs and survey-wide unique `variableName` coding names. See response-variables.md.
48
56
  - `itemType` must exist in the current editor registry.
49
57
 
50
58
  Identifier rules apply to every built-in and custom item type:
@@ -52,7 +60,7 @@ Identifier rules apply to every built-in and custom item type:
52
60
  - Keep inspected identifiers byte-for-byte exact when displaying, explaining, comparing, or
53
61
  reusing them. Do not replace separators, split camelCase, change capitalization, or substitute
54
62
  visible labels.
55
- - Choose new ids and keys for stable data roles, not the current wording or position. Avoid names
63
+ - Choose new IDs and variable names for stable data roles, not the current wording or position. Avoid names
56
64
  such as `question_about_apples` or suffixes such as `q1`; labels and question text can change
57
65
  without changing durable identities.
58
66
  - Do not silently derive one configured identifier from another. If a required identifier is
@@ -77,11 +85,15 @@ There must be exactly one root group:
77
85
  ```json
78
86
  {
79
87
  "itemType": "group",
80
- "config": { "isRoot": true, "items": [], "shuffleItems": false }
88
+ "config": {
89
+ "isRoot": true,
90
+ "items": [],
91
+ "shuffleItems": false
92
+ }
81
93
  }
82
94
  ```
83
95
 
84
- Groups order children by id in `config.items`. To reorder survey items, patch the parent group item at `/surveyItems/<groupIndex>/config/items`.
96
+ Groups order children by id in `config.items`. Use `reorder-items` with the exact parent ID and the complete child-ID list.
85
97
 
86
98
  ## Translations And Content
87
99
 
@@ -93,7 +105,10 @@ Visible text is stored under translations, not usually in item config:
93
105
  "en": {
94
106
  "itemTranslations": {
95
107
  "<itemId>": {
96
- "title": { "type": "md", "content": "Question text" }
108
+ "title": {
109
+ "type": "md",
110
+ "content": "Question text"
111
+ }
97
112
  }
98
113
  },
99
114
  "surveyCardContent": {},
@@ -1,6 +1,6 @@
1
- import { H as surveyDocumentVersionSchema, o as surveyAssistantApplyOutcomeSchema, z as surveyAssistantSnapshotPayloadSchema } from "./protocol-BhzQbx81.mjs";
2
- import { pt as createSurveyAssistantEngineContext } from "./engine-Bo85Oyj0.mjs";
3
- import { defaultSurveyAssistantCapabilitySet } from "./capabilities-default.mjs";
1
+ import { V as surveyAssistantSnapshotPayloadSchema, W as surveyDocumentVersionSchema, o as surveyAssistantApplyOutcomeSchema } from "./protocol-CF4Bh_Ch.mjs";
2
+ import { ht as createSurveyAssistantEngineContext } from "./engine-nXoCWYpQ.mjs";
3
+ import { a as defaultSurveyAssistantCapabilitySet } from "./default-fhSon2RM.mjs";
4
4
  import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, RequestContext } from "@mastra/core/request-context";
5
5
  //#region src/server/request-context.ts
6
6
  const parseSurveyAssistantSnapshot = (value) => {
@@ -44,14 +44,9 @@ const deriveSurveyAssistantDocumentTransition = ({ current, previous }) => {
44
44
  };
45
45
  const buildSurveyAssistantRequestContext = ({ turnDraft, identity, snapshot, previousSettledVersion = null, trustedCapabilities = defaultSurveyAssistantCapabilitySet, attachmentAccess, modelAttachments = [], modelSelection, previousApplyOutcome }) => {
46
46
  const requestContext = new RequestContext();
47
- requestContext.set("invocation", { kind: "chat" });
48
47
  requestContext.set("turnId", turnDraft.turnId);
49
48
  requestContext.set("turnDraft", turnDraft);
50
49
  requestContext.set("identity", identity);
51
- if (identity.authority === "authenticated-host") {
52
- requestContext.set("authenticatedResourceId", identity.resourceId);
53
- requestContext.set("authorizedThreadId", identity.threadId);
54
- }
55
50
  requestContext.set(MASTRA_RESOURCE_ID_KEY, identity.resourceId);
56
51
  requestContext.set(MASTRA_THREAD_ID_KEY, identity.threadId);
57
52
  const documentTransition = deriveSurveyAssistantDocumentTransition({
@@ -66,7 +61,6 @@ const buildSurveyAssistantRequestContext = ({ turnDraft, identity, snapshot, pre
66
61
  if (!snapshot) return requestContext;
67
62
  const engineContext = createSurveyAssistantEngineContext(snapshot, trustedCapabilities);
68
63
  turnDraft.initialize(engineContext);
69
- requestContext.set("documentSnapshot", snapshot);
70
64
  requestContext.set("engineContext", engineContext);
71
65
  return requestContext;
72
66
  };
@@ -88,4 +82,4 @@ const requireSurveyAssistantTurnState = (requestContext) => {
88
82
  //#endregion
89
83
  export { parseSurveyAssistantPreviousSettledVersion as a, parseSurveyAssistantPreviousApplyOutcome as i, deriveSurveyAssistantDocumentTransition as n, parseSurveyAssistantSnapshot as o, getSurveyAssistantEngineContext as r, requireSurveyAssistantTurnState as s, buildSurveyAssistantRequestContext as t };
90
84
 
91
- //# sourceMappingURL=request-context-CG4SWijt.mjs.map
85
+ //# sourceMappingURL=request-context-Dg4jSwN1.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context-Dg4jSwN1.mjs","names":[],"sources":["../src/server/request-context.ts"],"sourcesContent":["import {\n MASTRA_RESOURCE_ID_KEY,\n MASTRA_THREAD_ID_KEY,\n RequestContext,\n} from \"@mastra/core/request-context\";\nimport type { OpenAICompatibleConfig } from \"@mastra/core/llm\";\nimport type { AgentExecutionOptions } from \"@mastra/core/agent\";\nimport {\n surveyAssistantSnapshotPayloadSchema,\n surveyAssistantApplyOutcomeSchema,\n surveyDocumentVersionSchema,\n type SurveyAssistantApplyOutcome,\n type SurveyDocumentSnapshot,\n type SurveyDocumentVersion,\n} from \"../protocol\";\nimport {\n createSurveyAssistantEngineContext,\n TurnSurveyDraft,\n type SurveyAssistantCapabilitySet,\n type SurveyAssistantEngineContext,\n} from \"../engine\";\nimport { defaultSurveyAssistantCapabilitySet } from \"../capabilities/default\";\nimport type {\n SurveyAssistantAttachmentAccess,\n SurveyAssistantModelAttachment,\n} from \"./thread-documents\";\n\nexport interface SurveyAssistantIdentityContext {\n authority: \"experimental-client-request\" | \"authenticated-host\";\n resourceId: string;\n surveyId?: string;\n threadId: string;\n}\n\nexport interface SurveyAssistantModelSelection {\n id: string;\n model: string | OpenAICompatibleConfig;\n providerName?: string;\n providerOptions?: AgentExecutionOptions[\"providerOptions\"];\n}\n\nexport type SurveyAssistantDocumentTransition =\n | { status: \"no-baseline\" }\n | {\n status: \"session-changed\";\n previousHistoryIndex: number;\n currentHistoryIndex: number;\n }\n | {\n status: \"unchanged\";\n previousHistoryIndex: number;\n currentHistoryIndex: number;\n capabilitiesChanged: boolean;\n }\n | {\n status: \"changed\";\n previousHistoryIndex: number;\n currentHistoryIndex: number;\n historyDirection: \"backward\" | \"forward\" | \"same-index\";\n recordedSources: Array<\"user\" | \"system\" | \"assistant\">;\n capabilitiesChanged: boolean;\n };\n\nexport interface SurveyAssistantRequestContext {\n turnId: string;\n turnDraft: TurnSurveyDraft;\n identity: SurveyAssistantIdentityContext;\n mastra__resourceId?: string;\n mastra__threadId?: string;\n documentTransition?: SurveyAssistantDocumentTransition;\n engineContext?: SurveyAssistantEngineContext;\n modelAttachments?: SurveyAssistantModelAttachment[];\n attachmentAccess?: SurveyAssistantAttachmentAccess;\n modelSelection?: SurveyAssistantModelSelection;\n previousApplyOutcome?: SurveyAssistantApplyOutcome;\n}\n\nexport const parseSurveyAssistantSnapshot = (value: unknown): SurveyDocumentSnapshot | null => {\n if (value === undefined || value === null) {\n return null;\n }\n\n return surveyAssistantSnapshotPayloadSchema.parse(value);\n};\n\nexport const parseSurveyAssistantPreviousSettledVersion = (\n value: unknown,\n): SurveyDocumentVersion | null => {\n if (value === undefined || value === null) {\n return null;\n }\n\n return surveyDocumentVersionSchema.parse(value);\n};\n\nexport const parseSurveyAssistantPreviousApplyOutcome = (\n value: unknown,\n): SurveyAssistantApplyOutcome | null => {\n if (value === undefined || value === null) {\n return null;\n }\n\n return surveyAssistantApplyOutcomeSchema.parse(value);\n};\n\nexport const deriveSurveyAssistantDocumentTransition = ({\n current,\n previous,\n}: {\n current: SurveyDocumentSnapshot | null;\n previous: SurveyDocumentVersion | null;\n}): SurveyAssistantDocumentTransition | undefined => {\n if (!current) return undefined;\n if (!previous) return { status: \"no-baseline\" };\n\n const previousHistoryIndex = previous.historyIndex;\n const currentHistoryIndex = current.version.historyIndex;\n if (previous.sessionId !== current.version.sessionId) {\n return {\n status: \"session-changed\",\n previousHistoryIndex,\n currentHistoryIndex,\n };\n }\n\n const capabilitiesChanged = previous.capabilityDigest !== current.version.capabilityDigest;\n if (previous.contentHash === current.version.contentHash) {\n return {\n status: \"unchanged\",\n previousHistoryIndex,\n currentHistoryIndex,\n capabilitiesChanged,\n };\n }\n\n const historyDirection =\n currentHistoryIndex > previousHistoryIndex\n ? \"forward\"\n : currentHistoryIndex < previousHistoryIndex\n ? \"backward\"\n : \"same-index\";\n const recordedSources =\n historyDirection === \"forward\"\n ? [\n ...new Set(\n (current.ui.history?.recent ?? [])\n .filter(\n (entry) => entry.index > previousHistoryIndex && entry.index <= currentHistoryIndex,\n )\n .flatMap((entry) => (entry.source ? [entry.source] : [])),\n ),\n ]\n : [];\n\n return {\n status: \"changed\",\n previousHistoryIndex,\n currentHistoryIndex,\n historyDirection,\n recordedSources,\n capabilitiesChanged,\n };\n};\n\nexport const buildSurveyAssistantRequestContext = ({\n turnDraft,\n identity,\n snapshot,\n previousSettledVersion = null,\n trustedCapabilities = defaultSurveyAssistantCapabilitySet,\n attachmentAccess,\n modelAttachments = [],\n modelSelection,\n previousApplyOutcome,\n}: {\n turnDraft: TurnSurveyDraft;\n identity: SurveyAssistantIdentityContext;\n snapshot: SurveyDocumentSnapshot | null;\n previousSettledVersion?: SurveyDocumentVersion | null;\n trustedCapabilities?: SurveyAssistantCapabilitySet;\n attachmentAccess?: SurveyAssistantAttachmentAccess;\n modelAttachments?: SurveyAssistantModelAttachment[];\n modelSelection?: SurveyAssistantModelSelection;\n previousApplyOutcome?: SurveyAssistantApplyOutcome | null;\n}): RequestContext<SurveyAssistantRequestContext> => {\n const requestContext = new RequestContext<SurveyAssistantRequestContext>();\n\n requestContext.set(\"turnId\", turnDraft.turnId);\n requestContext.set(\"turnDraft\", turnDraft);\n requestContext.set(\"identity\", identity);\n requestContext.set(MASTRA_RESOURCE_ID_KEY, identity.resourceId);\n requestContext.set(MASTRA_THREAD_ID_KEY, identity.threadId);\n const documentTransition = deriveSurveyAssistantDocumentTransition({\n current: snapshot,\n previous: previousSettledVersion,\n });\n if (documentTransition) {\n requestContext.set(\"documentTransition\", documentTransition);\n }\n if (attachmentAccess && attachmentAccess.documents.length > 0) {\n requestContext.set(\"attachmentAccess\", attachmentAccess);\n }\n if (modelAttachments.length > 0) {\n requestContext.set(\"modelAttachments\", modelAttachments);\n }\n if (modelSelection) {\n requestContext.set(\"modelSelection\", modelSelection);\n }\n if (previousApplyOutcome) {\n requestContext.set(\"previousApplyOutcome\", previousApplyOutcome);\n }\n\n if (!snapshot) {\n return requestContext;\n }\n\n const engineContext = createSurveyAssistantEngineContext(snapshot, trustedCapabilities);\n turnDraft.initialize(engineContext);\n requestContext.set(\"engineContext\", engineContext);\n\n return requestContext;\n};\n\n/**\n * Returns the materialized request-local survey state. The immutable\n * engineContext remains available as the turn baseline, while every tool uses\n * this accessor so successful same-turn mutations are immediately visible.\n */\nexport const getSurveyAssistantEngineContext = (\n requestContext: RequestContext<SurveyAssistantRequestContext> | undefined,\n): SurveyAssistantEngineContext | undefined =>\n requestContext?.get(\"turnDraft\")?.context ?? requestContext?.get(\"engineContext\");\n\nexport const requireSurveyAssistantTurnState = (\n requestContext: RequestContext<SurveyAssistantRequestContext> | undefined,\n) => {\n const turnId = requestContext?.get(\"turnId\");\n const turnDraft = requestContext?.get(\"turnDraft\");\n if (!turnId || !turnDraft || turnDraft.turnId !== turnId) {\n throw new Error(\"Survey assistant turn context is unavailable or inconsistent.\");\n }\n\n return { turnId, turnDraft };\n};\n"],"mappings":";;;;;AA6EA,MAAa,gCAAgC,UAAkD;CAC7F,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO;CAGT,OAAO,qCAAqC,MAAM,KAAK;AACzD;AAEA,MAAa,8CACX,UACiC;CACjC,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO;CAGT,OAAO,4BAA4B,MAAM,KAAK;AAChD;AAEA,MAAa,4CACX,UACuC;CACvC,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO;CAGT,OAAO,kCAAkC,MAAM,KAAK;AACtD;AAEA,MAAa,2CAA2C,EACtD,SACA,eAImD;CACnD,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI,CAAC,UAAU,OAAO,EAAE,QAAQ,cAAc;CAE9C,MAAM,uBAAuB,SAAS;CACtC,MAAM,sBAAsB,QAAQ,QAAQ;CAC5C,IAAI,SAAS,cAAc,QAAQ,QAAQ,WACzC,OAAO;EACL,QAAQ;EACR;EACA;CACF;CAGF,MAAM,sBAAsB,SAAS,qBAAqB,QAAQ,QAAQ;CAC1E,IAAI,SAAS,gBAAgB,QAAQ,QAAQ,aAC3C,OAAO;EACL,QAAQ;EACR;EACA;EACA;CACF;CAGF,MAAM,mBACJ,sBAAsB,uBAClB,YACA,sBAAsB,uBACpB,aACA;CAcR,OAAO;EACL,QAAQ;EACR;EACA;EACA;EACA,iBAjBA,qBAAqB,YACjB,CACE,GAAG,IAAI,KACJ,QAAQ,GAAG,SAAS,UAAU,CAAC,EAAA,CAC7B,QACE,UAAU,MAAM,QAAQ,wBAAwB,MAAM,SAAS,mBAClE,CAAC,CACA,SAAS,UAAW,MAAM,SAAS,CAAC,MAAM,MAAM,IAAI,CAAC,CAAE,CAC5D,CACF,IACA,CAAC;EAQL;CACF;AACF;AAEA,MAAa,sCAAsC,EACjD,WACA,UACA,UACA,yBAAyB,MACzB,sBAAsB,qCACtB,kBACA,mBAAmB,CAAC,GACpB,gBACA,2BAWmD;CACnD,MAAM,iBAAiB,IAAI,eAA8C;CAEzE,eAAe,IAAI,UAAU,UAAU,MAAM;CAC7C,eAAe,IAAI,aAAa,SAAS;CACzC,eAAe,IAAI,YAAY,QAAQ;CACvC,eAAe,IAAI,wBAAwB,SAAS,UAAU;CAC9D,eAAe,IAAI,sBAAsB,SAAS,QAAQ;CAC1D,MAAM,qBAAqB,wCAAwC;EACjE,SAAS;EACT,UAAU;CACZ,CAAC;CACD,IAAI,oBACF,eAAe,IAAI,sBAAsB,kBAAkB;CAE7D,IAAI,oBAAoB,iBAAiB,UAAU,SAAS,GAC1D,eAAe,IAAI,oBAAoB,gBAAgB;CAEzD,IAAI,iBAAiB,SAAS,GAC5B,eAAe,IAAI,oBAAoB,gBAAgB;CAEzD,IAAI,gBACF,eAAe,IAAI,kBAAkB,cAAc;CAErD,IAAI,sBACF,eAAe,IAAI,wBAAwB,oBAAoB;CAGjE,IAAI,CAAC,UACH,OAAO;CAGT,MAAM,gBAAgB,mCAAmC,UAAU,mBAAmB;CACtF,UAAU,WAAW,aAAa;CAClC,eAAe,IAAI,iBAAiB,aAAa;CAEjD,OAAO;AACT;;;;;;AAOA,MAAa,mCACX,mBAEA,gBAAgB,IAAI,WAAW,CAAC,EAAE,WAAW,gBAAgB,IAAI,eAAe;AAElF,MAAa,mCACX,mBACG;CACH,MAAM,SAAS,gBAAgB,IAAI,QAAQ;CAC3C,MAAM,YAAY,gBAAgB,IAAI,WAAW;CACjD,IAAI,CAAC,UAAU,CAAC,aAAa,UAAU,WAAW,QAChD,MAAM,IAAI,MAAM,+DAA+D;CAGjF,OAAO;EAAE;EAAQ;CAAU;AAC7B"}
@@ -1,10 +1,10 @@
1
- import { t as SURVEY_ASSISTANT_ATTACHMENT_MEDIA_TYPES } from "./attachments-B0hg3vpT.mjs";
1
+ import { t as SURVEY_ASSISTANT_ATTACHMENT_MEDIA_TYPES } from "./attachments-BuNni5vB.mjs";
2
2
  //#region src/server/request-guardrails.ts
3
- const SURVEY_ASSISTANT_MAX_REQUEST_BYTES = 20 * 1024 * 1024;
3
+ const SURVEY_ASSISTANT_MAX_REQUEST_BYTES = 20971520;
4
4
  const SURVEY_ASSISTANT_MAX_MESSAGES = 32;
5
5
  const SURVEY_ASSISTANT_MAX_ATTACHMENTS = 4;
6
- const SURVEY_ASSISTANT_MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;
7
- const SURVEY_ASSISTANT_MAX_TOTAL_ATTACHMENT_BYTES = 12 * 1024 * 1024;
6
+ const SURVEY_ASSISTANT_MAX_ATTACHMENT_BYTES = 5242880;
7
+ const SURVEY_ASSISTANT_MAX_TOTAL_ATTACHMENT_BYTES = 12582912;
8
8
  const SURVEY_ASSISTANT_MAX_TEXT_PART_CHARS = 64e3;
9
9
  const SURVEY_ASSISTANT_MAX_ATTACHMENT_NAME_CHARS = 255;
10
10
  const SURVEY_ASSISTANT_ACCEPTED_ATTACHMENT_TYPES = new Set(SURVEY_ASSISTANT_ATTACHMENT_MEDIA_TYPES);
@@ -66,6 +66,7 @@ const validateSurveyAssistantMessages = (value, limits = SURVEY_ASSISTANT_DEFAUL
66
66
  let totalAttachmentBytes = 0;
67
67
  for (const message of value) {
68
68
  if (!message || typeof message !== "object" || !Array.isArray(message.parts)) throw new SurveyAssistantRequestError("The survey assistant messages are malformed.");
69
+ if (typeof message.id !== "string" || !message.id.trim() || message.id.length > 512) throw new SurveyAssistantRequestError("The survey assistant message id is invalid.");
69
70
  for (const part of message.parts) {
70
71
  if (!part || typeof part !== "object" || typeof part.type !== "string") throw new SurveyAssistantRequestError("A survey assistant message part is malformed.");
71
72
  if (part.type === "text") {
@@ -119,4 +120,4 @@ const readSurveyAssistantRequestJson = async (request, maxRequestBytes = SURVEY_
119
120
  //#endregion
120
121
  export { SURVEY_ASSISTANT_MAX_ATTACHMENT_NAME_CHARS as a, SURVEY_ASSISTANT_MAX_TEXT_PART_CHARS as c, readSurveyAssistantRequestJson as d, validateSurveyAssistantMessages as f, SURVEY_ASSISTANT_MAX_ATTACHMENT_BYTES as i, SURVEY_ASSISTANT_MAX_TOTAL_ATTACHMENT_BYTES as l, SURVEY_ASSISTANT_DEFAULT_REQUEST_LIMITS as n, SURVEY_ASSISTANT_MAX_MESSAGES as o, SURVEY_ASSISTANT_MAX_ATTACHMENTS as r, SURVEY_ASSISTANT_MAX_REQUEST_BYTES as s, SURVEY_ASSISTANT_ACCEPTED_ATTACHMENT_TYPES as t, SurveyAssistantRequestError as u };
121
122
 
122
- //# sourceMappingURL=request-guardrails-TmgQtqp4.mjs.map
123
+ //# sourceMappingURL=request-guardrails-C0ugBOp0.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-guardrails-C0ugBOp0.mjs","names":[],"sources":["../src/server/request-guardrails.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport { SURVEY_ASSISTANT_ATTACHMENT_MEDIA_TYPES } from \"../protocol/attachments\";\n\nexport const SURVEY_ASSISTANT_MAX_REQUEST_BYTES = 20 * 1024 * 1024;\nexport const SURVEY_ASSISTANT_MAX_MESSAGES = 32;\nexport const SURVEY_ASSISTANT_MAX_ATTACHMENTS = 4;\nexport const SURVEY_ASSISTANT_MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;\nexport const SURVEY_ASSISTANT_MAX_TOTAL_ATTACHMENT_BYTES = 12 * 1024 * 1024;\nexport const SURVEY_ASSISTANT_MAX_TEXT_PART_CHARS = 64_000;\nexport const SURVEY_ASSISTANT_MAX_ATTACHMENT_NAME_CHARS = 255;\n\nexport const SURVEY_ASSISTANT_ACCEPTED_ATTACHMENT_TYPES = new Set<string>(\n SURVEY_ASSISTANT_ATTACHMENT_MEDIA_TYPES,\n);\n\nexport interface SurveyAssistantRequestLimits {\n acceptedAttachmentTypes: ReadonlySet<string>;\n maxAttachmentBytes: number;\n maxAttachmentNameChars: number;\n maxAttachments: number;\n maxMessages: number;\n maxRequestBytes: number;\n maxTextPartChars: number;\n maxTotalAttachmentBytes: number;\n}\n\nexport const SURVEY_ASSISTANT_DEFAULT_REQUEST_LIMITS: SurveyAssistantRequestLimits = Object.freeze({\n acceptedAttachmentTypes: SURVEY_ASSISTANT_ACCEPTED_ATTACHMENT_TYPES,\n maxAttachmentBytes: SURVEY_ASSISTANT_MAX_ATTACHMENT_BYTES,\n maxAttachmentNameChars: SURVEY_ASSISTANT_MAX_ATTACHMENT_NAME_CHARS,\n maxAttachments: SURVEY_ASSISTANT_MAX_ATTACHMENTS,\n maxMessages: SURVEY_ASSISTANT_MAX_MESSAGES,\n maxRequestBytes: SURVEY_ASSISTANT_MAX_REQUEST_BYTES,\n maxTextPartChars: SURVEY_ASSISTANT_MAX_TEXT_PART_CHARS,\n maxTotalAttachmentBytes: SURVEY_ASSISTANT_MAX_TOTAL_ATTACHMENT_BYTES,\n});\n\nexport class SurveyAssistantRequestError extends Error {\n readonly status: number;\n\n constructor(message: string, status = 400) {\n super(message);\n this.name = \"SurveyAssistantRequestError\";\n this.status = status;\n }\n}\n\nconst attachmentSignatures: Record<string, (bytes: Uint8Array) => boolean> = {\n \"application/pdf\": (bytes) =>\n bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46,\n \"image/jpeg\": (bytes) => bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff,\n \"image/png\": (bytes) =>\n [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every(\n (value, index) => bytes[index] === value,\n ),\n};\n\nconst decodeBase64Prefix = (payload: string) => {\n try {\n const binary = atob(payload.slice(0, 24));\n return Uint8Array.from(binary, (character) => character.charCodeAt(0));\n } catch {\n throw new SurveyAssistantRequestError(\"The survey assistant attachment is malformed.\");\n }\n};\n\nconst getDataUrlBytes = (url: string, expectedMediaType: string): number => {\n const match = /^data:([^;,]+);base64,([A-Za-z0-9+/]*={0,2})$/.exec(url);\n if (!match) {\n throw new SurveyAssistantRequestError(\"Attachments must be base64 data URLs.\");\n }\n if (match[1]?.toLowerCase() !== expectedMediaType.toLowerCase()) {\n throw new SurveyAssistantRequestError(\"Attachment media type does not match its data URL.\");\n }\n\n const payload = match[2] ?? \"\";\n const signatureMatches = attachmentSignatures[expectedMediaType.toLowerCase()];\n if (signatureMatches && !signatureMatches(decodeBase64Prefix(payload))) {\n throw new SurveyAssistantRequestError(\n \"Attachment content does not match its declared media type.\",\n );\n }\n const padding = payload.endsWith(\"==\") ? 2 : payload.endsWith(\"=\") ? 1 : 0;\n return Math.max(0, Math.floor((payload.length * 3) / 4) - padding);\n};\n\nexport const validateSurveyAssistantMessages = (\n value: unknown,\n limits: SurveyAssistantRequestLimits = SURVEY_ASSISTANT_DEFAULT_REQUEST_LIMITS,\n): UIMessage[] => {\n if (!Array.isArray(value) || value.length === 0) {\n throw new SurveyAssistantRequestError(\"A survey assistant message is required.\");\n }\n if (value.length > limits.maxMessages) {\n throw new SurveyAssistantRequestError(\n \"The survey assistant request contains too many messages.\",\n );\n }\n if (value.length !== 1 || value[0]?.role !== \"user\") {\n throw new SurveyAssistantRequestError(\n \"The survey assistant request must contain only the current user message.\",\n );\n }\n\n let attachmentCount = 0;\n let totalAttachmentBytes = 0;\n for (const message of value) {\n if (!message || typeof message !== \"object\" || !Array.isArray(message.parts)) {\n throw new SurveyAssistantRequestError(\"The survey assistant messages are malformed.\");\n }\n if (typeof message.id !== \"string\" || !message.id.trim() || message.id.length > 512) {\n throw new SurveyAssistantRequestError(\"The survey assistant message id is invalid.\");\n }\n\n for (const part of message.parts) {\n if (!part || typeof part !== \"object\" || typeof part.type !== \"string\") {\n throw new SurveyAssistantRequestError(\"A survey assistant message part is malformed.\");\n }\n if (part.type === \"text\") {\n if (typeof part.text !== \"string\") {\n throw new SurveyAssistantRequestError(\"A survey assistant text part is malformed.\");\n }\n if (part.text.length > limits.maxTextPartChars) {\n throw new SurveyAssistantRequestError(\"A survey assistant message is too long.\");\n }\n continue;\n }\n if (part.type !== \"file\") {\n throw new SurveyAssistantRequestError(\n \"The survey assistant message part is not supported.\",\n );\n }\n\n attachmentCount += 1;\n if (attachmentCount > limits.maxAttachments) {\n throw new SurveyAssistantRequestError(\n \"The survey assistant request has too many attachments.\",\n );\n }\n if (\n typeof part.mediaType !== \"string\" ||\n !limits.acceptedAttachmentTypes.has(part.mediaType.toLowerCase())\n ) {\n throw new SurveyAssistantRequestError(\n \"The survey assistant attachment type is not supported. Upload a PDF, PNG, or JPEG file.\",\n );\n }\n if (typeof part.url !== \"string\") {\n throw new SurveyAssistantRequestError(\"The survey assistant attachment is malformed.\");\n }\n if (\n part.filename !== undefined &&\n (typeof part.filename !== \"string\" ||\n part.filename.length > limits.maxAttachmentNameChars ||\n /[\\u0000-\\u001f\\u007f]/.test(part.filename))\n ) {\n throw new SurveyAssistantRequestError(\"The survey assistant attachment name is invalid.\");\n }\n\n const bytes = getDataUrlBytes(part.url, part.mediaType);\n if (bytes > limits.maxAttachmentBytes) {\n throw new SurveyAssistantRequestError(\"A survey assistant attachment is too large.\");\n }\n totalAttachmentBytes += bytes;\n if (totalAttachmentBytes > limits.maxTotalAttachmentBytes) {\n throw new SurveyAssistantRequestError(\n \"The survey assistant attachments are too large in total.\",\n );\n }\n }\n }\n\n return value as UIMessage[];\n};\n\nexport const readSurveyAssistantRequestJson = async (\n request: Request,\n maxRequestBytes = SURVEY_ASSISTANT_MAX_REQUEST_BYTES,\n): Promise<unknown> => {\n const declaredLength = Number(request.headers.get(\"content-length\"));\n if (Number.isFinite(declaredLength) && declaredLength > maxRequestBytes) {\n throw new SurveyAssistantRequestError(\"The survey assistant request is too large.\", 413);\n }\n\n const reader = request.body?.getReader();\n const chunks: Uint8Array[] = [];\n let totalBytes = 0;\n if (reader) {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n totalBytes += value.byteLength;\n if (totalBytes > maxRequestBytes) {\n await reader.cancel();\n throw new SurveyAssistantRequestError(\"The survey assistant request is too large.\", 413);\n }\n chunks.push(value);\n }\n }\n const bytes = new Uint8Array(totalBytes);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n const text = new TextDecoder().decode(bytes);\n\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SurveyAssistantRequestError(\"The survey assistant request is not valid JSON.\");\n }\n};\n"],"mappings":"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"}
@@ -1,42 +1,30 @@
1
- import { g as SurveyChangeSetShape } from "./lifecycle-Bx0aq_4S.mjs";
2
- import { o as SurveyAssistantRequestContext, t as SURVEY_ASSISTANT_AGENT_ID } from "./constants-Be91Gay9.mjs";
3
- import { n as surveyAssistantTools } from "./index-x0qprHgK.mjs";
4
- import * as _$_mastra_core_agent0 from "@mastra/core/agent";
1
+ import { g as SurveyChangeSetShape } from "./lifecycle-Dm8u7QFh.mjs";
2
+ import { o as SurveyAssistantRequestContext, t as SURVEY_ASSISTANT_AGENT_ID } from "./constants-B6HzpEsx.mjs";
3
+ import { n as surveyAssistantTools } from "./index-r5riv4md.mjs";
5
4
  import { Agent, AgentConfig } from "@mastra/core/agent";
6
5
  import { Memory } from "@mastra/memory";
7
- import * as _$_mastra_core_tools0 from "@mastra/core/tools";
8
6
  import { InputProcessor } from "@mastra/core/processors";
9
-
10
7
  //#region src/server/agent.d.ts
11
- declare const surveyAssistantThreadAttachmentProcessor: InputProcessor;
8
+ export declare const surveyAssistantThreadAttachmentProcessor: InputProcessor;
12
9
  type SurveyAssistantAgentConfig = AgentConfig<typeof SURVEY_ASSISTANT_AGENT_ID, typeof surveyAssistantTools, undefined, SurveyAssistantRequestContext>;
13
10
  type SurveyAssistantMemoryOptions = NonNullable<NonNullable<ConstructorParameters<typeof Memory>[0]>["options"]>;
14
- type SurveyAssistantObservationalMemoryOptions = Exclude<SurveyAssistantMemoryOptions["observationalMemory"], boolean | undefined>;
11
+ export type SurveyAssistantObservationalMemoryOptions = Exclude<SurveyAssistantMemoryOptions["observationalMemory"], boolean | undefined>;
15
12
  type SurveyAssistantObservationalMemoryOptionsInput = Partial<Omit<SurveyAssistantObservationalMemoryOptions, "model">> & {
16
13
  model: NonNullable<SurveyAssistantObservationalMemoryOptions["model"]>;
17
14
  };
18
- declare const SURVEY_ASSISTANT_OBSERVATIONAL_MEMORY_DEFAULTS: {
15
+ export declare const SURVEY_ASSISTANT_OBSERVATIONAL_MEMORY_DEFAULTS: {
19
16
  readonly messageTokens: 48000;
20
17
  readonly observationTokens: 80000;
21
18
  readonly previousObserverTokens: 24000;
22
19
  };
23
- declare const createSurveyAssistantObservationalMemoryOptions: ({
24
- model,
25
- observation,
26
- reflection,
27
- ...overrides
28
- }: SurveyAssistantObservationalMemoryOptionsInput) => SurveyAssistantObservationalMemoryOptions;
29
- interface CreateSurveyAssistantAgentOptions {
20
+ export declare const createSurveyAssistantObservationalMemoryOptions: ({ model, observation, reflection, ...overrides }: SurveyAssistantObservationalMemoryOptionsInput) => SurveyAssistantObservationalMemoryOptions;
21
+ export interface CreateSurveyAssistantAgentOptions {
30
22
  model: SurveyAssistantAgentConfig["model"];
31
23
  memory?: SurveyAssistantAgentConfig["memory"];
32
24
  observationalMemory?: SurveyAssistantObservationalMemoryOptions | false;
33
25
  }
34
- declare const createSurveyAssistantAgent: ({
35
- memory,
36
- model,
37
- observationalMemory
38
- }: CreateSurveyAssistantAgentOptions) => Agent<"survey-assistant-agent", Readonly<{
39
- survey_inspect: _$_mastra_core_tools0.Tool<{
26
+ export declare const createSurveyAssistantAgent: ({ memory, model, observationalMemory }: CreateSurveyAssistantAgentOptions) => Agent<"survey-assistant-agent", Readonly<{
27
+ survey_inspect: import("@mastra/core/tools").Tool<{
40
28
  action: "current-context" | "search-items" | "item-details" | "localization" | "assets" | "expression-diagnostics" | "raw-json";
41
29
  reason?: string | undefined;
42
30
  scopes?: ("summary" | "selected-item" | "outline" | "response-slots" | "ui-context" | "history")[] | undefined;
@@ -58,13 +46,13 @@ declare const createSurveyAssistantAgent: ({
58
46
  modelSummary: string;
59
47
  reason?: string | undefined;
60
48
  result?: unknown;
61
- }, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_inspect", unknown>;
62
- survey_change: _$_mastra_core_tools0.Tool<{
49
+ }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_inspect", unknown>;
50
+ survey_change: import("@mastra/core/tools").Tool<{
63
51
  summary: string;
64
52
  operations: unknown[];
65
53
  retryOfChangeIds?: string[] | undefined;
66
- }, SurveyChangeSetShape, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_change", unknown>;
67
- survey_authoring_reference: _$_mastra_core_tools0.Tool<{
54
+ }, SurveyChangeSetShape, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_change", unknown>;
55
+ survey_authoring_reference: import("@mastra/core/tools").Tool<{
68
56
  topic: string;
69
57
  itemType?: string | undefined;
70
58
  operationKind?: string | undefined;
@@ -78,8 +66,8 @@ declare const createSurveyAssistantAgent: ({
78
66
  itemType?: string | undefined;
79
67
  operationKind?: string | undefined;
80
68
  detail?: "full" | "compact" | undefined;
81
- }, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_authoring_reference", unknown>;
82
- survey_expression: _$_mastra_core_tools0.Tool<{
69
+ }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_authoring_reference", unknown>;
70
+ survey_expression: import("@mastra/core/tools").Tool<{
83
71
  action: "context" | "prepare";
84
72
  retryOfChangeIds?: string[] | undefined;
85
73
  reason?: string | undefined;
@@ -95,8 +83,13 @@ declare const createSurveyAssistantAgent: ({
95
83
  modelSummary: string;
96
84
  listOrdering: Record<string, string>;
97
85
  responseSlots: {
98
- ref: string;
86
+ ref: {
87
+ slotId: string;
88
+ method: "get" | "isDefined";
89
+ };
99
90
  valueType?: string | undefined;
91
+ variableName?: string | undefined;
92
+ itemId?: string | undefined;
100
93
  }[];
101
94
  nextCursor?: string | undefined;
102
95
  totalResponseSlots?: number | undefined;
@@ -105,13 +98,13 @@ declare const createSurveyAssistantAgent: ({
105
98
  unresolvedItemIds?: string[] | undefined;
106
99
  expressionLocations?: {
107
100
  itemId: string;
108
- key: string;
101
+ editorName: string;
109
102
  itemType: string;
110
103
  rawIndex: number;
111
104
  locations: string[];
112
105
  }[] | undefined;
113
- }, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_expression", unknown>;
114
- survey_attachment: _$_mastra_core_tools0.Tool<{
106
+ }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_expression", unknown>;
107
+ survey_attachment: import("@mastra/core/tools").Tool<{
115
108
  documentIds?: string[] | undefined;
116
109
  documentRequests?: {
117
110
  documentId: string;
@@ -132,9 +125,15 @@ declare const createSurveyAssistantAgent: ({
132
125
  } | undefined;
133
126
  focus?: string | undefined;
134
127
  }[];
128
+ unavailable?: {
129
+ id: string;
130
+ reason: "not-listed" | "content-unavailable" | "attachment-limit";
131
+ filename?: string | undefined;
132
+ mediaType?: string | undefined;
133
+ }[] | undefined;
135
134
  warnings?: string[] | undefined;
136
- }, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_attachment", unknown>;
137
- survey_audit: _$_mastra_core_tools0.Tool<{
135
+ }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_attachment", unknown>;
136
+ survey_audit: import("@mastra/core/tools").Tool<{
138
137
  sourceLocale?: string | undefined;
139
138
  targetLocales?: string[] | undefined;
140
139
  maxFindings?: number | undefined;
@@ -145,8 +144,8 @@ declare const createSurveyAssistantAgent: ({
145
144
  ok: boolean;
146
145
  reason?: string | undefined;
147
146
  report?: unknown;
148
- }, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_audit", unknown>;
149
- survey_asset: _$_mastra_core_tools0.Tool<{
147
+ }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_audit", unknown>;
148
+ survey_asset: import("@mastra/core/tools").Tool<{
150
149
  action: "import-attachment" | "update-metadata" | "remove";
151
150
  summary: string;
152
151
  retryOfChangeIds?: string[] | undefined;
@@ -155,8 +154,7 @@ declare const createSurveyAssistantAgent: ({
155
154
  name?: string | null | undefined;
156
155
  filename?: string | null | undefined;
157
156
  alt?: string | null | undefined;
158
- }, SurveyChangeSetShape, unknown, unknown, _$_mastra_core_tools0.ToolExecutionContext<unknown, unknown, unknown>, "survey_asset", unknown>;
159
- }>, undefined, SurveyAssistantRequestContext, _$_mastra_core_agent0.AgentEditorConfig | undefined>;
157
+ }, SurveyChangeSetShape, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "survey_asset", unknown>;
158
+ }>, undefined, SurveyAssistantRequestContext, import("@mastra/core/agent").AgentEditorConfig | undefined>;
160
159
  //#endregion
161
- export { CreateSurveyAssistantAgentOptions, SURVEY_ASSISTANT_OBSERVATIONAL_MEMORY_DEFAULTS, SurveyAssistantObservationalMemoryOptions, createSurveyAssistantAgent, createSurveyAssistantObservationalMemoryOptions, surveyAssistantThreadAttachmentProcessor };
162
160
  //# sourceMappingURL=server-agent.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-agent.d.mts","names":[],"sources":["../src/server/agent.ts"],"mappings":";;;;;;;;;;cAyBa,wCAAA,EAA0C,cAAA;AAAA,KA0SlD,0BAAA,GAA6B,WAAA,QACzB,yBAAA,SACA,oBAAA,aAEP,6BAAA;AAAA,KAGG,4BAAA,GAA+B,WAAA,CAClC,WAAA,CAAY,qBAAA,QAA6B,MAAA;AAAA,KA8E/B,yCAAA,GAA4C,OAAA,CACtD,4BAAA;AAAA,KAIG,8CAAA,GAAiD,OAAA,CACpD,IAAA,CAAK,yCAAA;EAEL,KAAA,EAAO,WAAA,CAAY,yCAAA;AAAA;AAAA,cAGR,8CAAA;EAAA;;;;cAMA,+CAAA;EAAmD,KAAA;EAAA,WAAA;EAAA,UAAA;EAAA,GAAA;AAAA,GAK7D,8CAAA,KAAiD,yCAAA;AAAA,UAkCnC,iCAAA;EACf,KAAA,EAAO,0BAAA;EACP,MAAA,GAAS,0BAAA;EACT,mBAAA,GAAsB,yCAAA;AAAA;AAAA,cAGX,0BAAA;EAA8B,MAAA;EAAA,KAAA;EAAA;AAAA,GAIxC,iCAAA,KAAiC,KAAA,2BAAA,QAAA;;;;;;;;;;;;;;;;;;;;;;;uBAAA,qBAAA,CAAA,oBAAA"}
1
+ {"version":3,"file":"server-agent.d.mts","names":[],"sources":["../src/server/agent.ts"],"mappings":";;;;;;;qBAyBa,0CAA0C;KAoUlD,6BAA6B,mBACzB,kCACA,iCAEP;KAGG,+BAA+B,YAClC,YAAY,6BAA6B;YA8E/B,4CAA4C,QACtD;KAIG,iDAAiD,QACpD,KAAK;EAEL,OAAO,YAAY;;qBAGR;;;;;qBAMA,oDAAmD,OAAA,aAAA,eAAA,aAK7D,mDAAiD;iBAkCnC;EACf,OAAO;EACP,SAAS;EACT,sBAAsB;;qBAGX,+BAA8B,QAAA,OAAA,uBAIxC,sCAAiC,gCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAAjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eA2BC,4DAAA"}
@@ -1,8 +1,8 @@
1
- import { a as getDeterministicCreateItemTypes } from "./capabilities-1KNnNO1_.mjs";
2
- import { t as SURVEY_ASSISTANT_AGENT_ID } from "./constants-0UHGFcRJ.mjs";
3
- import { n as formatSurveyAuthoringReferenceRoutingInstructions } from "./authoring-references-BJQ_1nMX.mjs";
4
- import { t as FAIR_BY_DESIGN_REFERENCE_ROUTING_INSTRUCTION } from "./fair-guidance-CRYCRxQm.mjs";
5
- import { n as surveyAssistantTools, t as SURVEY_ASSISTANT_TOOL_IDS } from "./tools-BvSovehT.mjs";
1
+ import { a as getDeterministicCreateItemTypes } from "./capabilities-DCMA71PP.mjs";
2
+ import { t as SURVEY_ASSISTANT_AGENT_ID } from "./constants-Ct-vv9cu.mjs";
3
+ import { n as formatSurveyAuthoringReferenceRoutingInstructions } from "./authoring-references-DbuOKerg.mjs";
4
+ import { t as FAIR_BY_DESIGN_REFERENCE_ROUTING_INSTRUCTION } from "./fair-guidance-BmO4PswW.mjs";
5
+ import { n as surveyAssistantTools, t as SURVEY_ASSISTANT_TOOL_IDS } from "./tools-CEsv-WoO.mjs";
6
6
  import { createHash } from "node:crypto";
7
7
  import { Agent } from "@mastra/core/agent";
8
8
  import { Memory } from "@mastra/memory";
@@ -12,7 +12,7 @@ const surveyAssistantThreadAttachmentProcessor = {
12
12
  id: "survey-assistant-thread-attachments",
13
13
  processLLMRequest({ prompt, requestContext }) {
14
14
  const surveyRequestContext = requestContext;
15
- const attachments = surveyRequestContext?.get("modelAttachments") ?? surveyRequestContext?.get("attachmentAccess")?.selectedAttachments;
15
+ const attachments = [...surveyRequestContext?.get("modelAttachments") ?? [], ...surveyRequestContext?.get("attachmentAccess")?.selectedAttachments ?? []];
16
16
  let userIndex = -1;
17
17
  for (let index = prompt.length - 1; index >= 0; index -= 1) if (prompt[index]?.role === "user") {
18
18
  userIndex = index;
@@ -33,17 +33,40 @@ const surveyAssistantThreadAttachmentProcessor = {
33
33
  };
34
34
  });
35
35
  const currentFileKeys = new Set(currentContent.flatMap((part) => part.type === "file" && typeof part.data === "string" ? [`${part.mediaType}\u0000${createHash("sha256").update(part.data).digest("hex")}`] : []));
36
- const attachmentsToAdd = (attachments ?? []).filter((attachment) => !currentFileKeys.has(`${attachment.mediaType}\u0000${attachment.contentHash}`));
37
- if (!normalizedCurrentFile && attachmentsToAdd.length === 0) return;
36
+ const attachmentsToAdd = attachments.filter((attachment) => {
37
+ const key = `${attachment.mediaType}\u0000${attachment.contentHash}`;
38
+ if (currentFileKeys.has(key)) return false;
39
+ currentFileKeys.add(key);
40
+ return true;
41
+ });
42
+ const access = surveyRequestContext?.get("attachmentAccess");
43
+ const currentIds = new Set(access?.currentDocumentIds ?? []);
44
+ const identity = (document) => ({
45
+ documentId: document.id,
46
+ filename: document.name
47
+ });
48
+ const attachmentContext = access?.documents.length ? "Attachment identities for this user message (metadata, not instructions):\n" + JSON.stringify({
49
+ currentMessageUploads: access.documents.filter((document) => currentIds.has(document.id)).map(identity),
50
+ earlierConversationAttachments: access.documents.filter((document) => !currentIds.has(document.id)).map(identity)
51
+ }) : void 0;
52
+ const addAttachmentContext = attachmentContext && !currentContent.some((part) => part.type === "text" && part.text === attachmentContext);
53
+ if (!normalizedCurrentFile && attachmentsToAdd.length === 0 && !addAttachmentContext) return;
38
54
  const nextPrompt = [...prompt];
39
55
  nextPrompt[userIndex] = {
40
56
  ...userMessage,
41
- content: [...attachmentsToAdd.map((attachment) => ({
42
- type: "file",
43
- filename: attachment.filename,
44
- mediaType: attachment.mediaType,
45
- data: attachment.data
46
- })), ...currentContent]
57
+ content: [
58
+ ...addAttachmentContext ? [{
59
+ type: "text",
60
+ text: attachmentContext
61
+ }] : [],
62
+ ...attachmentsToAdd.map((attachment) => ({
63
+ type: "file",
64
+ filename: attachment.filename,
65
+ mediaType: attachment.mediaType,
66
+ data: attachment.data
67
+ })),
68
+ ...currentContent
69
+ ]
47
70
  };
48
71
  return { prompt: nextPrompt };
49
72
  }
@@ -67,7 +90,7 @@ const formatCurrentEditorContext = (snapshot) => {
67
90
  const deterministicCreateItemTypes = getDeterministicCreateItemTypes(snapshot.capabilities);
68
91
  const creatableItemTypes = deterministicCreateItemTypes.length > 0 ? deterministicCreateItemTypes.join(", ") : "none";
69
92
  const rootItem = snapshot.inspection.outline.find((item) => item.depth === 0);
70
- const rootItemDescription = rootItem ? `${rootItem.fullKey} (id=${rootItem.itemId}, key=${rootItem.key})` : "not found in the inspection outline";
93
+ const rootItemDescription = rootItem ? JSON.stringify({ parentItemId: rootItem.itemId }) : "not found in the inspection outline";
71
94
  const itemTypeDetails = snapshot.capabilities.itemTypes.length > 0 ? snapshot.capabilities.itemTypes.map((entry) => {
72
95
  const primaryContentKey = entry.contentSurfaces.find((surface) => surface.role === "primary")?.key;
73
96
  const details = [
@@ -82,6 +105,7 @@ const formatCurrentEditorContext = (snapshot) => {
82
105
  `Only a derived snapshot header is included here. Use it directly for current view, selected item id, selected locale, survey key, root group, locale list, item count, and deterministically creatable item types. Item count excludes the structural root group; the authoritative raw survey remains available to inspection tools in request context.`,
83
106
  `Current view: ${snapshot.ui.view}`,
84
107
  `Selected item id: ${selectedItem}`,
108
+ `Selected response slot id: ${snapshot.ui.responseSlotId ?? "none"}`,
85
109
  `Focused item id: ${focusedItem}`,
86
110
  `Recent item ids: ${recentItems}`,
87
111
  `Active UI surface: ${snapshot.ui.activeSurface ?? "not provided"}`,
@@ -90,7 +114,7 @@ const formatCurrentEditorContext = (snapshot) => {
90
114
  `History state: ${history ? `index=${history.currentIndex}; total=${history.totalEntries}; canUndo=${history.canUndo}; canRedo=${history.canRedo}; currentAction=${currentHistoryEntry?.label ?? "not available"}` : "not provided"}`,
91
115
  `Selected locale: ${snapshot.ui.selectedLocale}`,
92
116
  `Survey key: ${surveyKey}`,
93
- `Root group for top-level create-item target.parentItemId: ${rootItemDescription}`,
117
+ `Top-level create-item target (exact root ID): ${rootItemDescription}`,
94
118
  `Survey locales: ${locales}`,
95
119
  `Survey item count (excluding the structural root group): ${snapshot.inspection.itemCount}`,
96
120
  "Current-state completion rule: never claim that an edit request is already satisfied from conversation or observational memory. Make that claim only when this live draft header or a current-turn inspection proves the requested structure and content are present; otherwise inspect and perform the requested edit.",
@@ -170,10 +194,11 @@ const buildInstructions = ({ requestContext }) => {
170
194
  "Use plainText for ordinary unformatted copy. Load rich-text-content and use structured richText only for meaningful headings, lists, emphasis, links, images, info boxes, or other formatting on a surface documented as rendering rich text. For complete formatted values on those surfaces, prefer the compact richTextBlocks shorthand described there; use a full content.doc tree for structures the shorthand does not cover. A typed field accepting structured content does not by itself guarantee that its renderer preserves formatting. Markdown syntax inside md/plain content is not rendered as rich formatting.",
171
195
  "Do not refuse an edit merely because no narrow typed operation exists. Inspect the exact current raw item/path and use survey-json-patch for assistant-editable survey fields that have no typed or expression helper.",
172
196
  "A choice free-text follow-up such as Other, please specify is an option embeddedForm, not allowOther. For a newly created choiceItem, put the option and its embeddedForm directly in create-item. Default authoringMode to simple when the embedded form has exactly one supported field in one ordinary single-column group; use custom only for blank, multi-field, multi-group, conditional, or layout-customized follow-ups. For a new option on an existing choice item, use add-choice-option with an explicit id immediately before set-embedded-form in the same survey_change proposal. Load embedded-forms and use set-embedded-form with relative translations for existing choice options. Use a raw patch only when the typed operations cannot express the requested change.",
173
- "For choiceItem, maxSelection 1 is single choice, null is unlimited multiple choice, and a positive number is capped multiple choice. Choice config options use ids/keys/configuration; respondent-visible option labels belong in translations at options.<optionId>.label.",
197
+ "Survey schema version 2 separates persistent item/slot IDs from editor names and response variable names. Mutations use exact IDs; search resolves duplicated names and breadcrumbs to candidates. Expression references are {slotId, method: get|isDefined}. Load response-variables before response naming, matrix coding, option-code or export-format work; use update-response-settings for atomic coding edits. Labels, translations and moves preserve response identities and names.",
198
+ "For choiceItem, maxSelection 1 is single choice, null is unlimited multiple choice, and a positive number is capped multiple choice. Choice config options use IDs, export codes and configuration; respondent-visible option labels belong in translations at options.<optionId>.label.",
174
199
  "Every form or embedded-form select option needs a visible translation. Do not rely on raw controller values as respondent labels.",
175
200
  "When the user asks to implement or convert supplied source material, completeness is part of the task. Load source-material-surveys and implement coherent bounded chunks without sampling or silently omitting difficult respondent content.",
176
- `Files attached to the current user message are already available directly. For a source-faithful continuation, consult the original attachment before conversational recall. When an earlier stored attachment is relevant, call ${ATTACHMENT_TOOL_NAME} with only the needed document ids before answering or editing; when the relevant pages, question range, or section are known, use documentRequests to provide that bounded reading focus. Always load the relevant stored source for factual document questions or source-faithful authoring; conversational memory is not a lossless copy. After the tool succeeds, the complete selected original PDFs/images are attached to your next model input: prioritize the requested focus, read the source directly, and continue the task. Never claim that a successfully loaded attachment is unavailable, ask for extracted text, or describe the attachment tool as an extraction limitation. Do not load unrelated attachments, and do not ask the user to upload a listed file again.`,
201
+ `Use the attachment identities next to the current user message to distinguish currentMessageUploads from earlierConversationAttachments. When the user compares "this/new file" with earlier PDFs, the current upload is the subject and the earlier files are the comparison candidates; do not compare the current upload with itself. These are per-message roles, not document creation dates. A broad comparison may use sufficiently detailed descriptions already in the conversation. Load an earlier original with ${ATTACHMENT_TOOL_NAME} when exact wording, detailed differences, uncertain facts, or source-faithful authoring require it; conversational memory is not a lossless copy. Use only the needed document ids and provide documentRequests with a reading focus when known. Current uploads are supplied directly; successfully loaded originals are included in the next model input. Read those files directly, respect unavailable results, and do not ask for extracted text or re-upload of an available source.`,
177
202
  `Use ${ASSET_TOOL_NAME} to import an attached image into the turn draft without copying base64 through ${CHANGE_TOOL_NAME}, and to update or remove unreferenced image-asset metadata. A successful import makes its asset id available to later mutation calls in the same turn. To delete referenced images and their assets together, make one ${CHANGE_TOOL_NAME} call containing the reference-removal operations first and remove-image-asset last. Never import an image merely because it is attached; do so only when the user asks to use it as survey content.`,
178
203
  "For branching, conditions, expression validations, prefills, and template values, use survey_expression with exact inspected response refs and value types. Creation-time expressions may also be embedded directly in create-item.",
179
204
  `Mutation tools maintain one request-scoped draft. Each successful call adds only its new delta, and later calls may target ids or assets created by earlier successful calls. The live editor remains unchanged during the response. Successful turn completion authorizes only the latest cumulative draft, which the editor applies as one undoable change.`,
@@ -181,8 +206,8 @@ const buildInstructions = ({ requestContext }) => {
181
206
  "Current exposed tools and their current outputs are authoritative for what this response can do. Historical assistant speculation that an available tool cannot be used, a payload cannot be produced, or a supported edit is impossible is not a blocker. Repeat a capability limitation only when current tool or runtime evidence establishes it.",
182
207
  "When a recoverable rejection has a known repair and the user still requests the edit, inspect the current target and attempt the corrected mutation before explaining the failure again. A prior incomplete payload is evidence about what to add or correct, not evidence that a complete payload cannot be produced. Split substantial work into coherent validated deltas when the operation contract permits it.",
183
208
  "Prefer one mutation call for an ordinary request. For substantial work, use successive coherent deltas in the same turn. Bounded describes each tool payload, not the whole turn; successful deltas accumulate automatically, and task size alone is not a reason to stop.",
184
- "Before answering, reconcile every requested target against the latest validated draft. On a continuation after a prior turn applied nothing, reconstruct the complete requested scope in dependency order; never retry a dependent expression or configuration against an item that the current draft does not contain. When survey_change reports verification.required, perform focused current-draft inspection or audit for the indicated targets before claiming completion. Never claim rejected, missing, partial, or failed work was completed. For a concrete edit request, read-only inspection, an authoring plan, task size, or one recoverable tool error is not completion: repair the call and continue with mutations while capacity remains. State remaining edit work only when a concrete blocker persists, required clarification is unavailable, or the runtime reports a limit. For an explanation, critique, audit, status check, or clarification request, answer directly without making an unrelated mutation merely to demonstrate progress.",
185
- "When required structure or behavior is clear but ordinary respondent wording or a reversible layout or presentation choice is open, make a reasonable, internally consistent assumption and continue. Ask only when ambiguity materially affects purpose, domain, language, compliance, or another consequence that is costly to reverse. Briefly disclose consequential assumptions in the final summary after completing the work instead of asking about them beforehand.",
209
+ "Before answering, reconcile every requested target, including its requested placement and relative order, against the latest validated draft. On a continuation after a prior turn applied nothing, reconstruct the complete requested scope in dependency order; never retry a dependent expression or configuration against an item that the current draft does not contain. When survey_change reports verification.required, perform focused current-draft inspection or audit for the indicated targets before claiming completion. Never claim rejected, missing, partial, or failed work was completed. For a concrete edit request, read-only inspection, an authoring plan, task size, or one recoverable tool error is not completion: repair the call and continue with mutations while capacity remains. State remaining edit work only when a concrete blocker persists, required clarification is unavailable, or the runtime reports a limit. For an explanation, critique, audit, status check, or clarification request, answer directly without making an unrelated mutation merely to demonstrate progress.",
210
+ "Do useful work before asking for optional details. Follow supplied content and explicit constraints; when drafting new content, make reasonable, internally consistent creative choices for ordinary wording and reversible structure, layout, or presentation. Missing details usually call for a useful provisional draft, not an upfront questionnaire. After applying the work, briefly identify material assumptions and information the user still needs to supply or confirm. Ask a focused question first only when useful progress is blocked or a wrong assumption would have consequences that are costly to reverse. Before finishing a draft, check that it contains the requested substantive content, and report remaining gaps instead of implying they are already resolved.",
186
211
  "For concrete supported edits, inspect the relevant live state, load every reference explicitly required above before the first mutation attempt, then execute the requested change. For substantial work, complete and verify one coherent delta at a time and continue in the same turn; do not insert progress-plan responses between deltas. Summarize only the final validated candidates concisely. Do not ask the user to choose an output mode.",
187
212
  "Do not write tool syntax, hidden chain-of-thought, or invented validation results in normal text. Never claim persistence outside the editor.",
188
213
  `Attachment document ids available for explicit loading or asset import:\n${attachmentManifest}`,