@case-framework/survey-assistant 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{authoring-references-DYuOAdVx.mjs → authoring-references-yyYC4Ydi.mjs} +9 -3
- package/dist/authoring-references-yyYC4Ydi.mjs.map +1 -0
- package/dist/{capabilities-DlC1l6qy.d.mts → capabilities-CnsVuJ1k.d.mts} +12 -4
- package/dist/capabilities-CnsVuJ1k.d.mts.map +1 -0
- package/dist/capabilities-default.d.mts +1 -1
- package/dist/capabilities-default.d.mts.map +1 -1
- package/dist/capabilities-default.mjs +38 -4
- package/dist/capabilities-default.mjs.map +1 -1
- package/dist/{constants-D-5m_KGB.d.mts → constants-DrGZXtQf.d.mts} +12 -7
- package/dist/constants-DrGZXtQf.d.mts.map +1 -0
- package/dist/{controller-proxy-0WJZUZYx.mjs → controller-proxy-CpkQRezb.mjs} +3 -2
- package/dist/controller-proxy-CpkQRezb.mjs.map +1 -0
- package/dist/{controller-proxy-Hkuub9dt.d.mts → controller-proxy-DmBdzqKs.d.mts} +5 -2
- package/dist/controller-proxy-DmBdzqKs.d.mts.map +1 -0
- package/dist/{digest-BvXpeWcR.d.mts → digest-Dyjch_sC.d.mts} +2 -2
- package/dist/{digest-BvXpeWcR.d.mts.map → digest-Dyjch_sC.d.mts.map} +1 -1
- package/dist/digest.d.mts +1 -1
- package/dist/{engine-0AJrv0hI.mjs → engine-CWTuN3o2.mjs} +866 -663
- package/dist/engine-CWTuN3o2.mjs.map +1 -0
- package/dist/engine.d.mts +3 -3
- package/dist/engine.mjs +3 -3
- package/dist/fair-guidance-CEdJYccK.mjs +21 -0
- package/dist/fair-guidance-CEdJYccK.mjs.map +1 -0
- package/dist/form-authoring-DCd9XfXf.mjs +155 -0
- package/dist/form-authoring-DCd9XfXf.mjs.map +1 -0
- package/dist/{index-JXH-t2EJ.d.mts → index-Bo4dHAo8.d.mts} +68 -6
- package/dist/index-Bo4dHAo8.d.mts.map +1 -0
- package/dist/{index-MEOL9_Gr.d.mts → index-D4OitUg4.d.mts} +5 -430
- package/dist/index-D4OitUg4.d.mts.map +1 -0
- package/dist/{index-BcyfBeDj.d.mts → index-DZk20e3k.d.mts} +44 -22
- package/dist/index-DZk20e3k.d.mts.map +1 -0
- package/dist/{index-CneD8ibB.d.mts → index-Dxgg0-D_.d.mts} +12 -3
- package/dist/index-Dxgg0-D_.d.mts.map +1 -0
- package/dist/lifecycle-DWv5CiSu.d.mts +523 -0
- package/dist/lifecycle-DWv5CiSu.d.mts.map +1 -0
- package/dist/{memory-thread-repository-1ocPOda8.mjs → memory-thread-repository-acbz6HZJ.mjs} +181 -26
- package/dist/memory-thread-repository-acbz6HZJ.mjs.map +1 -0
- package/dist/{protocol-DpCYmCjr.mjs → protocol-DATvkr1S.mjs} +125 -6
- package/dist/protocol-DATvkr1S.mjs.map +1 -0
- package/dist/protocol.d.mts +4 -3
- package/dist/protocol.mjs +2 -2
- package/dist/{react-DXK5zWNo.mjs → react-Br5YE8H-.mjs} +132 -12
- package/dist/react-Br5YE8H-.mjs.map +1 -0
- package/dist/react-integration.d.mts +1 -1
- package/dist/react-integration.mjs +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.mjs +2 -2
- package/dist/references/assistant-operations.md +13 -18
- package/dist/references/embedded-forms.md +41 -2
- package/dist/references/expressions.md +17 -9
- package/dist/references/fair-by-design.md +80 -0
- package/dist/references/item-types.md +19 -3
- package/dist/references/localization.md +7 -4
- package/dist/references/source-material-surveys.md +6 -4
- package/dist/{request-context-BBzU3VdG.mjs → request-context-BEjnaaFr.mjs} +10 -5
- package/dist/request-context-BEjnaaFr.mjs.map +1 -0
- package/dist/server-agent.d.mts +44 -22
- package/dist/server-agent.d.mts.map +1 -1
- package/dist/server-agent.mjs +71 -14
- package/dist/server-agent.mjs.map +1 -1
- package/dist/server-runtime.d.mts +22 -11
- package/dist/server-runtime.d.mts.map +1 -1
- package/dist/server-runtime.mjs +47 -19
- package/dist/server-runtime.mjs.map +1 -1
- package/dist/server-tasks.d.mts +1 -1
- package/dist/server-tasks.mjs +6 -4
- package/dist/server-tasks.mjs.map +1 -1
- package/dist/server-tools.d.mts +1 -1
- package/dist/server-tools.mjs +1 -1
- package/dist/server.d.mts +16 -7
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +4 -4
- package/dist/storage-postgres.d.mts +1 -1
- package/dist/{tasks-DcfQNJwO.d.mts → tasks-DQgL449A.d.mts} +8 -4
- package/dist/tasks-DQgL449A.d.mts.map +1 -0
- package/dist/{thread-documents-BlxNjc7S.d.mts → thread-documents-Dvo6XS7o.d.mts} +1 -1
- package/dist/{thread-documents-BlxNjc7S.d.mts.map → thread-documents-Dvo6XS7o.d.mts.map} +1 -1
- package/dist/{thread-handlers-uddXwQjp.d.mts → thread-handlers-CeYl45xG.d.mts} +9 -4
- package/dist/thread-handlers-CeYl45xG.d.mts.map +1 -0
- package/dist/{tools-wgLen05n.mjs → tools-Dg9HZrYU.mjs} +404 -78
- package/dist/tools-Dg9HZrYU.mjs.map +1 -0
- package/dist/ui.css +2 -2
- package/dist/ui.d.mts +94 -10
- package/dist/ui.d.mts.map +1 -1
- package/dist/ui.mjs +343 -112
- package/dist/ui.mjs.map +1 -1
- package/docs/integration.md +74 -6
- package/package.json +25 -19
- package/dist/authoring-references-DYuOAdVx.mjs.map +0 -1
- package/dist/capabilities-DKbNCnBf.mjs +0 -66
- package/dist/capabilities-DKbNCnBf.mjs.map +0 -1
- package/dist/capabilities-DlC1l6qy.d.mts.map +0 -1
- package/dist/constants-D-5m_KGB.d.mts.map +0 -1
- package/dist/controller-proxy-0WJZUZYx.mjs.map +0 -1
- package/dist/controller-proxy-Hkuub9dt.d.mts.map +0 -1
- package/dist/engine-0AJrv0hI.mjs.map +0 -1
- package/dist/index-BcyfBeDj.d.mts.map +0 -1
- package/dist/index-CneD8ibB.d.mts.map +0 -1
- package/dist/index-JXH-t2EJ.d.mts.map +0 -1
- package/dist/index-MEOL9_Gr.d.mts.map +0 -1
- package/dist/memory-thread-repository-1ocPOda8.mjs.map +0 -1
- package/dist/protocol-DpCYmCjr.mjs.map +0 -1
- package/dist/react-DXK5zWNo.mjs.map +0 -1
- package/dist/request-context-BBzU3VdG.mjs.map +0 -1
- package/dist/tasks-DcfQNJwO.d.mts.map +0 -1
- package/dist/thread-handlers-uddXwQjp.d.mts.map +0 -1
- package/dist/tools-wgLen05n.mjs.map +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { A as getRawSurvey, B as resolveItemSummary, C as clampLimit, F as mapKeyIndexById, H as summarizeFocusItemNode, I as mapOutlineById, J as translationEntrySchema, K as summarizeOutlineNode, L as mapRawItemsById, M as itemConfigDetailsSchema, N as itemMatchesQuery, P as itemSummarySchema, R as normalizeText, U as summarizeItemById, V as sliceWithCursor, W as summarizeKeyIndexEntries, Y as unique, _ as buildConfigSearchText, b as buildItemTranslationEntries, d as normalizeSurveyChangeOperations, f as buildExpressionMutationPatches, j as getRawSurveyItems, k as getKeyIndexEntries, l as createSurveyChangeSet, p as expressionMutationSchema, q as summarizeRawItem,
|
|
4
|
-
import {
|
|
5
|
-
import { n as
|
|
1
|
+
import { X as SURVEY_OPERATION_KINDS, bt as surveyOperationSchemasByKind, f as surveyChangeSetSchema, q as assistantItemTypeManifestSchema, yt as surveyOperationSchema } from "./protocol-DATvkr1S.mjs";
|
|
2
|
+
import { d as getDeterministicCreateItemTypes, f as inspectAssistantItem, p as resolveAssistantCapabilityReference } from "./form-authoring-DCd9XfXf.mjs";
|
|
3
|
+
import { A as getRawSurvey, B as resolveItemSummary, C as clampLimit, F as mapKeyIndexById, H as summarizeFocusItemNode, I as mapOutlineById, J as translationEntrySchema, K as summarizeOutlineNode, L as mapRawItemsById, M as itemConfigDetailsSchema, N as itemMatchesQuery, P as itemSummarySchema, R as normalizeText, U as summarizeItemById, V as sliceWithCursor, W as summarizeKeyIndexEntries, Y as unique, _ as buildConfigSearchText, b as buildItemTranslationEntries, d as normalizeSurveyChangeOperations, f as buildExpressionMutationPatches, i as auditSurvey, j as getRawSurveyItems, k as getKeyIndexEntries, l as createSurveyChangeSet, p as expressionMutationSchema, q as summarizeRawItem, v as buildEmbeddedFormDetails, w as findDirectChildrenByFullKey, y as buildItemConfigDetails } from "./engine-CWTuN3o2.mjs";
|
|
4
|
+
import { r as getSurveyAssistantEngineContext, s as requireSurveyAssistantTurnState } from "./request-context-BEjnaaFr.mjs";
|
|
5
|
+
import { i as surveyAuthoringReferences, n as getBuiltInItemTypeAuthoringReference, r as surveyAuthoringReferenceTopics, t as builtInSurveyAuthoringItemTypes } from "./authoring-references-yyYC4Ydi.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
|
-
import { JsonPatchError, SURVEY_EDITOR_ITEM_COLORS, encodeJsonPointerSegment, getAssetUsagesFromContent, getValueAtJsonPointer } from "@case-framework/survey-core";
|
|
7
|
+
import { JsonPatchError, SURVEY_EDITOR_ITEM_COLORS, encodeJsonPointerSegment, getAssetUsagesFromContent, getContentPlainText, getValueAtJsonPointer } from "@case-framework/survey-core";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { createTool, isValidationError } from "@mastra/core/tools";
|
|
10
10
|
//#region src/server/operation-contract-reference.ts
|
|
11
11
|
const isSurveyOperationKind = (value) => SURVEY_OPERATION_KINDS.includes(value);
|
|
12
12
|
const SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS = ["compact", "full"];
|
|
13
|
-
const isRecord$
|
|
13
|
+
const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
14
|
const summarizeLargeSchema = (schema, propertyName) => {
|
|
15
15
|
const description = typeof schema.description === "string" ? schema.description : propertyName ? `Canonical value for "${propertyName}".` : "Canonical value.";
|
|
16
16
|
const type = typeof schema.type === "string" ? schema.type : void 0;
|
|
@@ -21,7 +21,7 @@ const summarizeLargeSchema = (schema, propertyName) => {
|
|
|
21
21
|
};
|
|
22
22
|
const compactJsonSchema = (value, propertyName, depth = 0) => {
|
|
23
23
|
if (Array.isArray(value)) return value.map((entry) => compactJsonSchema(entry, propertyName, depth + 1));
|
|
24
|
-
if (!isRecord$
|
|
24
|
+
if (!isRecord$2(value)) return value;
|
|
25
25
|
if (typeof value.$ref === "string") return { description: "Recursive structured value omitted from this compact reference; request full detail only for protocol debugging." };
|
|
26
26
|
if (depth >= 3 && JSON.stringify(value).length > 12e3) return summarizeLargeSchema(value, propertyName);
|
|
27
27
|
const compact = {};
|
|
@@ -39,7 +39,7 @@ const compactJsonSchema = (value, propertyName, depth = 0) => {
|
|
|
39
39
|
"required",
|
|
40
40
|
"additionalProperties"
|
|
41
41
|
]) if (value[key] !== void 0) compact[key] = value[key];
|
|
42
|
-
if (isRecord$
|
|
42
|
+
if (isRecord$2(value.properties)) compact.properties = Object.fromEntries(Object.entries(value.properties).map(([key, schema]) => [key, compactJsonSchema(schema, key, depth + 1)]));
|
|
43
43
|
if (value.items !== void 0) compact.items = compactJsonSchema(value.items, propertyName, depth + 1);
|
|
44
44
|
for (const unionKey of ["oneOf", "anyOf"]) if (Array.isArray(value[unionKey])) compact[unionKey] = value[unionKey].map((entry) => compactJsonSchema(entry, propertyName, depth + 1));
|
|
45
45
|
return compact;
|
|
@@ -54,6 +54,7 @@ const formatItemCapabilityProfile = (manifest, kind) => {
|
|
|
54
54
|
`${manifest.displayName}: ${manifest.description ?? "No additional description."}`,
|
|
55
55
|
`Creation mode: ${manifest.create}.`,
|
|
56
56
|
manifest.authoring?.configSummary ? `Configuration: ${manifest.authoring.configSummary}` : void 0,
|
|
57
|
+
manifest.creationPresets?.length ? `Available creation preset ids: ${manifest.creationPresets.map((preset) => `\`${preset.id}\``).join(", ")}. Use the server-trusted configuration guidance above for their semantics.` : void 0,
|
|
57
58
|
fixedSurfaces.length > 0 ? `Fixed content surfaces: ${fixedSurfaces.map((surface) => surface.key).join(", ")}.` : "Fixed content surfaces: none.",
|
|
58
59
|
patternedSurfaces.length > 0 ? `Dynamic content surfaces: ${patternedSurfaces.map((surface) => surface.key).join(", ")}.` : void 0,
|
|
59
60
|
kind === "create-item" && requiredSurfaces.length > 0 ? `Required on creation: ${requiredSurfaces.map((surface) => surface.key).join(", ")}.` : void 0,
|
|
@@ -87,6 +88,55 @@ const formatSurveyOperationContractReference = (kind, options = {}) => {
|
|
|
87
88
|
].join("\n");
|
|
88
89
|
};
|
|
89
90
|
//#endregion
|
|
91
|
+
//#region src/server/canonical-name-suggestions.ts
|
|
92
|
+
const CANONICAL_ACTION_TOKENS = {
|
|
93
|
+
add: "create",
|
|
94
|
+
append: "create",
|
|
95
|
+
create: "create",
|
|
96
|
+
delete: "remove",
|
|
97
|
+
edit: "update",
|
|
98
|
+
insert: "create",
|
|
99
|
+
modify: "update",
|
|
100
|
+
patch: "update",
|
|
101
|
+
relocate: "move",
|
|
102
|
+
remove: "remove",
|
|
103
|
+
reorder: "reorder",
|
|
104
|
+
replace: "update",
|
|
105
|
+
set: "update",
|
|
106
|
+
sort: "reorder",
|
|
107
|
+
update: "update"
|
|
108
|
+
};
|
|
109
|
+
const tokenizeCanonicalName = (value) => value.normalize("NFKD").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean).map((token) => CANONICAL_ACTION_TOKENS[token] ?? token);
|
|
110
|
+
const editDistance = (left, right) => {
|
|
111
|
+
const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
112
|
+
for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
|
|
113
|
+
const current = [leftIndex];
|
|
114
|
+
for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) current[rightIndex] = Math.min((current[rightIndex - 1] ?? 0) + 1, (previous[rightIndex] ?? 0) + 1, (previous[rightIndex - 1] ?? 0) + (left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1));
|
|
115
|
+
previous.splice(0, previous.length, ...current);
|
|
116
|
+
}
|
|
117
|
+
return previous[right.length] ?? 0;
|
|
118
|
+
};
|
|
119
|
+
const scoreCanonicalName = (input, candidate) => {
|
|
120
|
+
const inputTokens = tokenizeCanonicalName(input);
|
|
121
|
+
const candidateTokens = tokenizeCanonicalName(candidate);
|
|
122
|
+
const normalizedInput = inputTokens.join("-");
|
|
123
|
+
const normalizedCandidate = candidateTokens.join("-");
|
|
124
|
+
if (!normalizedInput || !normalizedCandidate) return 0;
|
|
125
|
+
if (normalizedInput === normalizedCandidate) return 4;
|
|
126
|
+
const maximumLength = Math.max(normalizedInput.length, normalizedCandidate.length);
|
|
127
|
+
const similarity = 1 - editDistance(normalizedInput, normalizedCandidate) / maximumLength;
|
|
128
|
+
const candidateTokenSet = new Set(candidateTokens);
|
|
129
|
+
const tokenCoverage = inputTokens.filter((token) => candidateTokenSet.has(token)).length / Math.max(inputTokens.length, candidateTokens.length);
|
|
130
|
+
const sameFinalToken = inputTokens.at(-1) === candidateTokens.at(-1) ? .5 : 0;
|
|
131
|
+
const sameFirstToken = inputTokens[0] === candidateTokens[0] ? .2 : 0;
|
|
132
|
+
return similarity + tokenCoverage + sameFinalToken + sameFirstToken;
|
|
133
|
+
};
|
|
134
|
+
/** Suggests registry-derived canonical names without silently accepting an alias. */
|
|
135
|
+
const suggestCanonicalNames = (input, candidates, limit = 3) => [...new Set(candidates)].filter((candidate) => candidate !== input).map((candidate) => ({
|
|
136
|
+
candidate,
|
|
137
|
+
score: scoreCanonicalName(input, candidate)
|
|
138
|
+
})).filter((entry) => entry.score >= .9).sort((left, right) => right.score - left.score || left.candidate.localeCompare(right.candidate)).slice(0, Math.max(0, limit)).map((entry) => entry.candidate);
|
|
139
|
+
//#endregion
|
|
90
140
|
//#region src/server/tools/tool-model-output.ts
|
|
91
141
|
const FALLBACK_MODEL_TEXT = "The tool returned no model-readable output. Review the tool arguments and retry with valid values.";
|
|
92
142
|
const unwrapToolOutput$1 = (value) => value && typeof value === "object" && "output" in value && value.output !== void 0 ? value.output : value;
|
|
@@ -110,25 +160,31 @@ const toTextModelOutput = (value, summarize) => {
|
|
|
110
160
|
//#region src/server/tools/survey-authoring-reference-tool.ts
|
|
111
161
|
const TOOL_ID$10 = "survey_authoring_reference";
|
|
112
162
|
const topicSchema = z.string().min(1).max(120);
|
|
163
|
+
const inputSchema$10 = z.object({
|
|
164
|
+
topic: topicSchema.describe("The narrow authoring reference to load."),
|
|
165
|
+
itemType: z.string().min(1).max(120).optional().describe("Installed item type to focus. With topic \"item-types\", returns only that item type section instead of the combined reference."),
|
|
166
|
+
operationKind: z.string().min(1).max(120).optional().describe("For topic assistant-operations, return only this operation's generated canonical field contract."),
|
|
167
|
+
detail: z.enum(SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS).optional().describe("Contract detail for assistant-operations. Use \"compact\" for authoring and \"full\" only for protocol debugging."),
|
|
168
|
+
reason: z.string().max(500).optional().describe("Short reason this reference is needed.")
|
|
169
|
+
});
|
|
170
|
+
const outputSchema$8 = z.object({
|
|
171
|
+
ok: z.boolean(),
|
|
172
|
+
topic: topicSchema,
|
|
173
|
+
itemType: z.string().optional(),
|
|
174
|
+
operationKind: z.string().optional(),
|
|
175
|
+
detail: z.enum(SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS).optional(),
|
|
176
|
+
title: z.string(),
|
|
177
|
+
content: z.string()
|
|
178
|
+
});
|
|
179
|
+
const formatCanonicalNameRecovery = (input, candidates, noun) => {
|
|
180
|
+
const suggestions = suggestCanonicalNames(input, candidates);
|
|
181
|
+
return suggestions.length > 0 ? ` Closest canonical ${noun}${suggestions.length === 1 ? "" : "s"}: ${suggestions.map((value) => `"${value}"`).join(", ")}. Retry with the intended canonical name.` : " Retry without the focused name to load the available catalog.";
|
|
182
|
+
};
|
|
113
183
|
const surveyAuthoringReferenceTool = createTool({
|
|
114
184
|
id: TOOL_ID$10,
|
|
115
185
|
description: "Load one narrow CASE authoring reference. With topic \"item-types\", pass itemType to load only that type. For a survey_change operation, use topic \"assistant-operations\" with operationKind and optionally itemType to compose the structural contract with that installed item capability. Compact detail is the authoring default; full detail is only for protocol debugging.",
|
|
116
|
-
inputSchema:
|
|
117
|
-
|
|
118
|
-
itemType: z.string().min(1).max(120).optional().describe("Installed item type to focus. With topic \"item-types\", returns only that item type section instead of the combined reference."),
|
|
119
|
-
operationKind: z.string().min(1).max(120).optional().describe("For topic assistant-operations, return only this operation's generated canonical field contract."),
|
|
120
|
-
detail: z.enum(SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS).optional().describe("Contract detail for assistant-operations. Use \"compact\" for authoring and \"full\" only for protocol debugging."),
|
|
121
|
-
reason: z.string().max(500).optional().describe("Short reason this reference is needed.")
|
|
122
|
-
}),
|
|
123
|
-
outputSchema: z.object({
|
|
124
|
-
ok: z.boolean(),
|
|
125
|
-
topic: topicSchema,
|
|
126
|
-
itemType: z.string().optional(),
|
|
127
|
-
operationKind: z.string().optional(),
|
|
128
|
-
detail: z.enum(SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS).optional(),
|
|
129
|
-
title: z.string(),
|
|
130
|
-
content: z.string()
|
|
131
|
-
}),
|
|
186
|
+
inputSchema: inputSchema$10,
|
|
187
|
+
outputSchema: outputSchema$8,
|
|
132
188
|
mcp: { annotations: {
|
|
133
189
|
title: "Read authoring reference",
|
|
134
190
|
readOnlyHint: true,
|
|
@@ -140,6 +196,7 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
140
196
|
const contractDetail = inputData.detail ?? "compact";
|
|
141
197
|
const engineContext = getSurveyAssistantEngineContext(context?.requestContext);
|
|
142
198
|
const itemCapability = inputData.itemType ? engineContext?.trustedCapabilities?.byItemType.get(inputData.itemType)?.manifest ?? engineContext?.capabilities.itemTypes.find((entry) => entry.itemType === inputData.itemType) : void 0;
|
|
199
|
+
const availableItemTypes = [...builtInSurveyAuthoringItemTypes, ...engineContext?.capabilities.itemTypes.map((entry) => entry.itemType) ?? []];
|
|
143
200
|
if (inputData.operationKind && inputData.topic !== "assistant-operations") return {
|
|
144
201
|
ok: false,
|
|
145
202
|
topic: inputData.topic,
|
|
@@ -155,16 +212,16 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
155
212
|
operationKind: inputData.operationKind,
|
|
156
213
|
detail: contractDetail,
|
|
157
214
|
title: "Operation contract unavailable",
|
|
158
|
-
content: `No built-in survey_change operation named "${inputData.operationKind}" is available.`
|
|
215
|
+
content: `No built-in survey_change operation named "${inputData.operationKind}" is available.` + formatCanonicalNameRecovery(inputData.operationKind, SURVEY_OPERATION_KINDS, "operation")
|
|
159
216
|
};
|
|
160
|
-
if (inputData.itemType && !itemCapability) return {
|
|
217
|
+
if (inputData.itemType && !itemCapability && !getBuiltInItemTypeAuthoringReference(inputData.itemType)) return {
|
|
161
218
|
ok: false,
|
|
162
219
|
topic: inputData.topic,
|
|
163
220
|
itemType: inputData.itemType,
|
|
164
221
|
operationKind: inputData.operationKind,
|
|
165
222
|
detail: contractDetail,
|
|
166
223
|
title: "Item capability unavailable",
|
|
167
|
-
content: `No installed survey item capability named "${inputData.itemType}" is available.`
|
|
224
|
+
content: `No installed survey item capability named "${inputData.itemType}" is available.` + formatCanonicalNameRecovery(inputData.itemType, availableItemTypes, "item type")
|
|
168
225
|
};
|
|
169
226
|
if (itemCapability && !itemCapability.supportedOperations.includes(inputData.operationKind)) return {
|
|
170
227
|
ok: false,
|
|
@@ -196,6 +253,13 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
196
253
|
topic: inputData.topic
|
|
197
254
|
}) : void 0;
|
|
198
255
|
const focusedBuiltInItemTypeReference = inputData.topic === "item-types" && inputData.itemType ? getBuiltInItemTypeAuthoringReference(inputData.itemType) : void 0;
|
|
256
|
+
if (inputData.itemType && !focusedBuiltInItemTypeReference && !capability && !capabilityReference) return {
|
|
257
|
+
ok: false,
|
|
258
|
+
topic: inputData.topic,
|
|
259
|
+
itemType: inputData.itemType,
|
|
260
|
+
title: "Item capability unavailable",
|
|
261
|
+
content: `No installed survey item capability named "${inputData.itemType}" is available.` + formatCanonicalNameRecovery(inputData.itemType, availableItemTypes, "item type")
|
|
262
|
+
};
|
|
199
263
|
const capabilityEntry = capabilityReference ? {
|
|
200
264
|
title: capabilityReference.title ?? `${capability?.manifest.displayName} authoring`,
|
|
201
265
|
content: capabilityReference.markdown
|
|
@@ -207,7 +271,7 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
207
271
|
itemType: inputData.itemType,
|
|
208
272
|
operationKind: inputData.operationKind,
|
|
209
273
|
title: "Reference unavailable",
|
|
210
|
-
content: inputData.itemType ? `No reference named "${inputData.topic}" is installed for item type "${inputData.itemType}".` : `No built-in reference named "${inputData.topic}" is available.`
|
|
274
|
+
content: (inputData.itemType ? `No reference named "${inputData.topic}" is installed for item type "${inputData.itemType}".` : `No built-in reference named "${inputData.topic}" is available.`) + formatCanonicalNameRecovery(inputData.topic, surveyAuthoringReferenceTopics, "reference")
|
|
211
275
|
};
|
|
212
276
|
return {
|
|
213
277
|
ok: true,
|
|
@@ -229,7 +293,8 @@ const OPERATIONS_DESCRIPTION = [
|
|
|
229
293
|
"Any translations owned by an operation must be inside that same operation object. Never put translations beside the survey_change operations array.",
|
|
230
294
|
"Create items with { kind: \"create-item\", target: { parentItemId, index? }, item: { id?, key, itemType, config }, translations? }. Put respondent content in top-level translations and item settings in item.config.",
|
|
231
295
|
"Use update-item-translation with itemId, locale, contentKey, and plainText for ordinary text or content for a complete structured value. Item titles and option/field labels are translations, not item labels.",
|
|
232
|
-
"Use
|
|
296
|
+
"Use add-survey-locale only when the user explicitly requests an empty language registration. An ordinary localization request requires real translation operations, which introduce the locale themselves.",
|
|
297
|
+
"Use remove-survey-locale with locale to destructively remove an existing survey language and all translations stored for it.",
|
|
233
298
|
"Each call adds a delta to this turn's validated draft. Later calls may target ids created by earlier successful calls in the same turn.",
|
|
234
299
|
"For an existing choice item, use add-choice-option with itemId, optional locale/index, and option: { id?, key?, label }; label is a plain string and creates its translation.",
|
|
235
300
|
"Every reorder replaces the complete inspected list: reorder-choice-options uses optionIds, reorder-form-field-groups uses groupIds, and reorder-items uses itemIds for every direct child. Include every existing entry exactly once in desired order.",
|
|
@@ -238,7 +303,7 @@ const OPERATIONS_DESCRIPTION = [
|
|
|
238
303
|
"Use update-placed-image only for an image placement that already exists in the live survey or validated turn draft.",
|
|
239
304
|
"When deleting referenced images and assets, include every reference-removal operation and remove-image-asset last in the same operations array.",
|
|
240
305
|
"Raw fallback is one { kind: \"survey-json-patch\", patches } operation containing all related survey-rooted edits; it must be the only operation in the call.",
|
|
241
|
-
"Keep each delta bounded;
|
|
306
|
+
"Keep each delta bounded; this is a per-call constraint, not a reason to end the turn. Successful chunks accumulate automatically, so substantial requests should continue with later deltas while capacity remains."
|
|
242
307
|
].join(" ");
|
|
243
308
|
const inputSchema$9 = z.object({
|
|
244
309
|
summary: z.string().min(1).max(500).describe("Short user-facing summary of the intended survey change."),
|
|
@@ -289,6 +354,7 @@ const describeOperationTarget = (operation) => {
|
|
|
289
354
|
case "update-survey-metadata":
|
|
290
355
|
case "update-survey-pagination": return operation.kind;
|
|
291
356
|
case "update-survey-translation": return `${operation.kind} ${operation.locale}:${operation.surface}:${operation.contentKey}`;
|
|
357
|
+
case "add-survey-locale":
|
|
292
358
|
case "remove-survey-locale": return `${operation.kind} ${operation.locale}`;
|
|
293
359
|
case "set-image-asset":
|
|
294
360
|
case "update-image-asset-metadata":
|
|
@@ -300,20 +366,48 @@ const describeOperationTarget = (operation) => {
|
|
|
300
366
|
const summarizeValidation = (event) => {
|
|
301
367
|
const lines = [`${event.status === "validated" ? "Validated" : "Rejected"} survey change: ${event.summary}`];
|
|
302
368
|
if (event.status === "rejected") {
|
|
303
|
-
lines.push("Draft unchanged. Fix this same rejected target in another call; the previously validated draft is retained. An unrelated valid edit does not repair this rejection.");
|
|
369
|
+
lines.push("TURN APPLY STATE: BLOCKED. Draft unchanged. This rejection does not finalize the editor or end the active turn. Fix this same rejected target in another survey_change call; the previously validated request-local draft is retained only for that repair. An unrelated valid edit does not repair this rejection.", "If this response ends while the turn is blocked, no prepared change from this turn, including every previously validated change, will reach the live editor. Do not tell the user that request-local draft content exists in the editor; either repair the rejected target now or state that none of this turn's changes were applied.");
|
|
304
370
|
if (event.operations.length > 0) {
|
|
305
371
|
const checklist = event.operations.slice(0, 24).map(describeOperationTarget);
|
|
306
372
|
lines.push(`Unapplied target sample (${checklist.length} of ${event.operations.length}):\n${checklist.map((target) => `- ${target}`).join("\n")}`);
|
|
307
373
|
if (event.operations.length > checklist.length) lines.push(`The sample omits ${event.operations.length - checklist.length} additional operation target(s). The original tool input is authoritative; preserve its complete requested scope when retrying.`);
|
|
308
374
|
}
|
|
309
375
|
}
|
|
310
|
-
if (event.status === "validated")
|
|
376
|
+
if (event.status === "validated") {
|
|
377
|
+
lines.push(`Draft updated (${event.operations.length} total operation${event.operations.length === 1 ? "" : "s"}). Later tools can inspect and edit the resulting draft state. The live editor is unchanged until successful turn completion.`);
|
|
378
|
+
if (event.postChange) {
|
|
379
|
+
const unavailableItemCount = event.postChange.touchedItemCount - event.postChange.availableTouchedItemCount;
|
|
380
|
+
lines.push(`Canonical post-change preview (first occurrence in operation order; projected fields only): ${event.postChange.itemCount} survey item(s); locales ${event.postChange.locales.length}/${event.postChange.localeCount} shown; targets ${event.postChange.touchedTargets.length}/${event.postChange.targetCount} shown; available touched-item snapshots ${event.postChange.touchedItems.length}/${event.postChange.availableTouchedItemCount} shown${unavailableItemCount > 0 ? `; ${unavailableItemCount} touched item target(s) are absent after the change` : ""}.`);
|
|
381
|
+
lines.push(`Target preview: ${event.postChange.touchedTargets.join(", ") || "none"}. Absence from this bounded projection does not prove that a field or target is absent from the canonical draft.`);
|
|
382
|
+
for (const item of event.postChange.touchedItems) {
|
|
383
|
+
const translations = item.translations.map(({ contentKey, locale, textLength, textPreview, truncated }) => truncated ? `${locale}:${contentKey}=${JSON.stringify(`${textPreview}…`)} [truncated preview; ${textLength} characters total]` : `${locale}:${contentKey}=${JSON.stringify(textPreview)}`).join("; ");
|
|
384
|
+
lines.push(`- ${item.fullKey} (${item.itemType}, id ${item.itemId}); response slots ${item.responseSlots.length}/${item.responseSlotCount}: ${item.responseSlots.join(", ") || "none"}; translations ${item.translations.length}/${item.translationCount}: ${translations || "none"}`);
|
|
385
|
+
}
|
|
386
|
+
if (event.postChange.truncated) lines.push("The post-change preview is truncated. The validated draft still contains the complete change; inspect any relevant omitted target or field before claiming its exact post-change value.");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (event.verification) {
|
|
390
|
+
lines.push(`Verification required before claiming completion (${event.verification.reasons.join(", ")}). Inspect the exact affected targets in the current draft; validation alone does not prove source fidelity or every omitted preview value.`);
|
|
391
|
+
if (event.verification.newAuditFindingCount > 0) {
|
|
392
|
+
lines.push(`New deterministic audit findings: ${event.verification.auditFindings.length}/${event.verification.newAuditFindingCount} shown.`);
|
|
393
|
+
for (const finding of event.verification.auditFindings) {
|
|
394
|
+
const location = [
|
|
395
|
+
finding.itemId,
|
|
396
|
+
finding.locale,
|
|
397
|
+
finding.contentKey
|
|
398
|
+
].filter(Boolean).join(":");
|
|
399
|
+
lines.push(`- ${finding.severity} ${finding.code}${location ? ` (${location})` : ""}: ${finding.messagePreview}${finding.truncated ? `… [truncated preview; ${finding.messageLength} characters total]` : ""}`);
|
|
400
|
+
}
|
|
401
|
+
if (event.verification.truncated) lines.push("Verification diagnostics are bounded. Use survey_audit or focused survey_inspect calls for the complete relevant state.");
|
|
402
|
+
}
|
|
403
|
+
}
|
|
311
404
|
if (event.validation.issues.length > 0) {
|
|
312
405
|
lines.push("Issues:");
|
|
313
406
|
for (const issue of event.validation.issues) lines.push(`- ${issue.code}: ${issue.message}`);
|
|
314
407
|
const issueCodes = new Set(event.validation.issues.map((issue) => issue.code));
|
|
315
|
-
if (issueCodes.has("missing-create-content") || issueCodes.has("missing-field-groups-wrapper") || issueCodes.has("missing-choice-options") || issueCodes.has("missing-choice-option-labels")) lines.push("Recovery hint: load the assistant-operations reference, then retry only the rejected delta. Put visible text in top-level translations[] beside item, config inside item.config, choice options in item.config.options, and form fields inside item.config.fieldGroups[].fields. Every choice option id needs a matching top-level translation whose contentKey is options.<optionId>.label.");
|
|
408
|
+
if (issueCodes.has("missing-create-content") || issueCodes.has("missing-field-groups-wrapper") || issueCodes.has("missing-choice-options") || issueCodes.has("missing-choice-option-labels") || issueCodes.has("missing-form-field-content") || issueCodes.has("missing-form-select-option-labels") || issueCodes.has("missing-form-field-labels") || issueCodes.has("missing-embedded-form-field-labels")) lines.push("Recovery hint: load the assistant-operations reference, then retry only the rejected delta. Put visible text in top-level translations[] beside item, config inside item.config, choice options in item.config.options, and form fields inside item.config.fieldGroups[].fields. Every choice option id needs a matching top-level translation whose contentKey is options.<optionId>.label.");
|
|
316
409
|
if (issueCodes.has("too-many-operations")) lines.push("Recovery hint: keep the same inspected survey context and split this rejected delta into smaller survey_change calls. Each successful call extends the same turn draft.");
|
|
410
|
+
if (issueCodes.has("item-already-in-target-parent")) lines.push("Recovery hint: remove unchanged same-parent move-item operations. To change sibling order within one parent, inspect its complete current children and use reorder-items instead.");
|
|
317
411
|
}
|
|
318
412
|
if (event.validation.warnings.length > 0) {
|
|
319
413
|
lines.push("Warnings:");
|
|
@@ -366,12 +460,12 @@ const prepareActionSchema = z.object({
|
|
|
366
460
|
mutations: z.array(expressionMutationSchema).min(1).max(40)
|
|
367
461
|
});
|
|
368
462
|
const inputSchema$8 = z.object({
|
|
369
|
-
action: z.enum(["context", "prepare"]).describe("
|
|
463
|
+
action: z.enum(["context", "prepare"]).describe("Choose exactly one envelope. Inspect with { \"action\": \"context\", \"itemIds\"?: [...], \"includeRawLocations\"?: true, \"reason\"?: \"...\" }; omit summary and mutations. Create edits with { \"action\": \"prepare\", \"summary\": \"...\", \"mutations\": [...] }; omit reason, itemIds, and includeRawLocations."),
|
|
370
464
|
reason: z.string().max(500).optional(),
|
|
371
|
-
itemIds: z.array(z.string().min(1).max(240)).max(12).optional().describe("
|
|
372
|
-
includeRawLocations: z.boolean().optional().describe("
|
|
373
|
-
summary: z.string().min(1).max(500).optional().describe("
|
|
374
|
-
mutations: z.array(z.record(z.string(), z.unknown())).min(1).max(40).optional().describe("
|
|
465
|
+
itemIds: z.array(z.string().min(1).max(240)).max(12).optional().describe("Context action only: optional item ids/keys to focus existing expression locations. Omit for prepare."),
|
|
466
|
+
includeRawLocations: z.boolean().optional().describe("Context action only: include existing expression locations by raw item. Omit for prepare."),
|
|
467
|
+
summary: z.string().min(1).max(500).optional().describe("Prepare action only: required user-facing summary. Omit for context."),
|
|
468
|
+
mutations: z.array(z.record(z.string(), z.unknown())).min(1).max(40).optional().describe("Prepare action only: required expression mutation objects using kebab-case kind names; omit this field for context. Item visibility shape: { kind: \"set-item-display-condition\", itemId: \"<existing-item-id>\", expression: { type: \"function\", functionName: \"eq\", arguments: [...] } }. expression is always CASE expression JSON, never a string or expression-language snippet. Other supported kinds set/clear component display/disabled conditions, validation expressions, prefills, and template values.")
|
|
375
469
|
}).strict().superRefine((value, ctx) => {
|
|
376
470
|
if (value.action !== "prepare") return;
|
|
377
471
|
if (!value.summary) ctx.addIssue({
|
|
@@ -442,7 +536,7 @@ const rejectedEvent = ({ issues, summary, turnId, warnings = [] }) => ({
|
|
|
442
536
|
const summarizeDraftEvent = (event) => {
|
|
443
537
|
const lines = [`${event.status === "validated" ? "Validated" : "Rejected"} expression change: ${event.summary}`];
|
|
444
538
|
if (event.status === "validated") lines.push(`Draft updated (${event.operations.length} total operation${event.operations.length === 1 ? "" : "s"}). The expression is immediately visible to later tools in this turn.`);
|
|
445
|
-
if (event.status === "rejected") lines.push("Draft unchanged. Fix this same expression target; the previously validated draft is retained. An unrelated valid edit does not repair this rejection.");
|
|
539
|
+
if (event.status === "rejected") lines.push("TURN APPLY STATE: BLOCKED. Draft unchanged. Fix this same expression target; the previously validated request-local draft is retained only for that repair. An unrelated valid edit does not repair this rejection.", "If this response ends while the turn is blocked, no prepared change from this turn, including every previously validated change, will reach the live editor. Do not tell the user that request-local draft content exists in the editor; either repair the rejected target now or state that none of this turn's changes were applied.");
|
|
446
540
|
if (event.validation.issues.length > 0) {
|
|
447
541
|
lines.push("Issues:");
|
|
448
542
|
for (const issue of event.validation.issues) lines.push(`- ${issue.code}: ${issue.message}`);
|
|
@@ -1009,7 +1103,7 @@ const summarizeConfigDetails = (configDetails) => {
|
|
|
1009
1103
|
for (const option of configDetails.choiceOptions ?? []) {
|
|
1010
1104
|
lines.push(`- ${option.position}. option ${option.key ?? option.id} (id=${option.id}, labelContentKey=${option.labelContentKey})`);
|
|
1011
1105
|
if (option.embeddedFormItemId || option.embeddedFormFieldGroupCount) {
|
|
1012
|
-
lines.push(` embedded form: itemId=${option.embeddedFormItemId ?? "inline"}, fieldGroups=${option.embeddedFormFieldGroupCount ?? 0}`);
|
|
1106
|
+
lines.push(` embedded form: itemId=${option.embeddedFormItemId ?? "inline"}, fieldGroups=${option.embeddedFormFieldGroupCount ?? 0}, authoringMode=${option.embeddedFormAuthoringMode ?? "custom"}, simpleModeValid=${option.embeddedFormSimpleModeValid ?? true}`);
|
|
1013
1107
|
if (option.embeddedFormTranslationPrefix || option.embeddedFormResponseSlotPrefix) lines.push(` embedded form keys: translationPrefix=${option.embeddedFormTranslationPrefix ?? "n/a"}, responseSlotPrefix=${option.embeddedFormResponseSlotPrefix ?? "n/a"}`);
|
|
1014
1108
|
}
|
|
1015
1109
|
}
|
|
@@ -1172,9 +1266,9 @@ const outputSchema$4 = z.object({
|
|
|
1172
1266
|
error: z.string().optional()
|
|
1173
1267
|
})).optional()
|
|
1174
1268
|
});
|
|
1175
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1269
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1176
1270
|
const getGroupChildren = (item) => {
|
|
1177
|
-
if (!isRecord(item) || !isRecord(item.config) || !Array.isArray(item.config.items)) return [];
|
|
1271
|
+
if (!isRecord$1(item) || !isRecord$1(item.config) || !Array.isArray(item.config.items)) return [];
|
|
1178
1272
|
return item.config.items.filter((entry) => typeof entry === "string");
|
|
1179
1273
|
};
|
|
1180
1274
|
const buildParentByChildId = (rawSurvey) => {
|
|
@@ -1267,7 +1361,7 @@ const buildItemValues = (snapshot, input) => {
|
|
|
1267
1361
|
const itemId = resolved.item.id;
|
|
1268
1362
|
const rawItemOutput = toOutputValue(resolved.item, input.valueCharacterLimit);
|
|
1269
1363
|
const translationsOutput = toOutputValue(getTranslationsByLocaleForItem(rawSurvey, itemId), input.valueCharacterLimit);
|
|
1270
|
-
const translationsValue = "value" in translationsOutput && isRecord(translationsOutput.value) ? translationsOutput.value : void 0;
|
|
1364
|
+
const translationsValue = "value" in translationsOutput && isRecord$1(translationsOutput.value) ? translationsOutput.value : void 0;
|
|
1271
1365
|
return {
|
|
1272
1366
|
identifier,
|
|
1273
1367
|
found: true,
|
|
@@ -1585,6 +1679,7 @@ const inspectActionSchema = z.enum([
|
|
|
1585
1679
|
"current-context",
|
|
1586
1680
|
"search-items",
|
|
1587
1681
|
"item-details",
|
|
1682
|
+
"localization",
|
|
1588
1683
|
"assets",
|
|
1589
1684
|
"raw-json"
|
|
1590
1685
|
]);
|
|
@@ -1593,6 +1688,8 @@ const outlineModeSchema = z.enum([
|
|
|
1593
1688
|
"focused",
|
|
1594
1689
|
"children"
|
|
1595
1690
|
]);
|
|
1691
|
+
const MAX_RAW_JSON_PATHS_PER_RESULT = 20;
|
|
1692
|
+
const MAX_RAW_JSON_PATHS_PER_REQUEST = 100;
|
|
1596
1693
|
const optionalInput = (schema) => z.preprocess((value) => value === null ? void 0 : value, schema.optional());
|
|
1597
1694
|
const optionalArrayInput = (schema) => z.preprocess((value) => value === null || Array.isArray(value) && value.length === 0 ? void 0 : value, schema.optional());
|
|
1598
1695
|
const optionalNonBlankString = (maxLength) => z.preprocess((value) => value === null || typeof value === "string" && value.trim().length === 0 ? void 0 : value, z.string().min(1).max(maxLength).optional());
|
|
@@ -1608,10 +1705,13 @@ const inputSchema$3 = z.object({
|
|
|
1608
1705
|
"history"
|
|
1609
1706
|
])).min(1).max(6)).describe("For current-context: context sections to inspect. Empty means omitted."),
|
|
1610
1707
|
query: optionalNonBlankString(180).describe("For search-items: text to search across survey content. For assets: optional asset id, filename, name, ALT text, or media type filter. For current-context outline: optional key/fullKey/label filter."),
|
|
1708
|
+
sourceLocale: optionalNonBlankString(40).describe("For localization: source locale to translate. Defaults to the selected editor locale."),
|
|
1709
|
+
targetLocale: optionalNonBlankString(40).describe("For localization: required target locale whose coverage should be inspected."),
|
|
1710
|
+
missingOnly: optionalInput(z.boolean()).describe("For localization: return only source surfaces that do not yet exist in the target locale."),
|
|
1611
1711
|
itemRef: optionalNonBlankString(240).describe("For current-context outline, item-details, or raw-json: item id, key, fullKey, visible label, or \"selected\"."),
|
|
1612
|
-
cursor: optionalNonBlankString(240).describe("For current-context
|
|
1712
|
+
cursor: optionalNonBlankString(240).describe("For current-context, search-items, or localization pagination: numeric cursor from a previous result."),
|
|
1613
1713
|
outlineMode: optionalInput(outlineModeSchema).describe("For current-context outline: \"full\" pages all survey items, \"focused\" returns the selected/focused neighborhood, and \"children\" returns direct children of itemRef."),
|
|
1614
|
-
paths: optionalArrayInput(z.array(z.string().min(1).max(500)).min(1).max(
|
|
1714
|
+
paths: optionalArrayInput(z.array(z.string().min(1).max(500)).min(1).max(MAX_RAW_JSON_PATHS_PER_REQUEST)).describe(`For raw-json: exact JSON Pointer paths to inspect in request order. itemRef takes precedence when both are supplied. Up to ${MAX_RAW_JSON_PATHS_PER_RESULT} paths are returned per call; larger valid requests receive explicit coverage and retry guidance instead of failing input validation. Empty means omitted.`),
|
|
1615
1715
|
includeChildren: optionalInput(z.boolean()).describe("For item-details: include direct survey-tree children."),
|
|
1616
1716
|
includeItemConfig: optionalInput(z.boolean()).describe("For item-details: include choice/form/internal item config details."),
|
|
1617
1717
|
limit: optionalInput(z.number().int().min(1).max(50)).describe("Maximum list rows to return.")
|
|
@@ -1636,6 +1736,89 @@ const stringifyForModel = (value) => {
|
|
|
1636
1736
|
if (typeof value === "string") return value;
|
|
1637
1737
|
return JSON.stringify(value, null, 2);
|
|
1638
1738
|
};
|
|
1739
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1740
|
+
const MAX_LOCALIZATION_TEXT_CHARS = 2e3;
|
|
1741
|
+
const SURVEY_TRANSLATION_SURFACES = [
|
|
1742
|
+
"surveyCardContent",
|
|
1743
|
+
"navigationContent",
|
|
1744
|
+
"validationMessages"
|
|
1745
|
+
];
|
|
1746
|
+
const truncateLocalizationText = (content) => {
|
|
1747
|
+
const text = getContentPlainText(content).trim();
|
|
1748
|
+
return text.length > MAX_LOCALIZATION_TEXT_CHARS ? `${text.slice(0, MAX_LOCALIZATION_TEXT_CHARS)}...` : text;
|
|
1749
|
+
};
|
|
1750
|
+
const listLocalizationSurfaces = (input, snapshot, targetLocale) => {
|
|
1751
|
+
const survey = snapshot.survey;
|
|
1752
|
+
const sourceLocale = input.sourceLocale ?? snapshot.ui.selectedLocale;
|
|
1753
|
+
const sourceTranslations = survey.translations?.[sourceLocale];
|
|
1754
|
+
const targetTranslations = survey.translations?.[targetLocale];
|
|
1755
|
+
if (!sourceTranslations) return {
|
|
1756
|
+
ok: false,
|
|
1757
|
+
reason: `Source locale "${sourceLocale}" is not present in the current survey draft.`
|
|
1758
|
+
};
|
|
1759
|
+
const surfaces = [];
|
|
1760
|
+
const addSurface = ({ contentKey, itemId, itemKey, itemType, sourceContent, surface, targetContent }) => {
|
|
1761
|
+
const sourceText = truncateLocalizationText(sourceContent);
|
|
1762
|
+
if (!sourceText) return;
|
|
1763
|
+
surfaces.push({
|
|
1764
|
+
scope: itemId ? "item" : "survey",
|
|
1765
|
+
...surface ? { surface } : {},
|
|
1766
|
+
...itemId ? {
|
|
1767
|
+
itemId,
|
|
1768
|
+
itemKey,
|
|
1769
|
+
itemType
|
|
1770
|
+
} : {},
|
|
1771
|
+
contentKey,
|
|
1772
|
+
sourceType: sourceContent.type,
|
|
1773
|
+
sourceText,
|
|
1774
|
+
...sourceContent.type === "richText" ? { sourceContent } : {},
|
|
1775
|
+
targetPresent: Boolean(targetContent && truncateLocalizationText(targetContent)),
|
|
1776
|
+
...targetContent ? {
|
|
1777
|
+
targetType: targetContent.type,
|
|
1778
|
+
targetText: truncateLocalizationText(targetContent)
|
|
1779
|
+
} : {}
|
|
1780
|
+
});
|
|
1781
|
+
};
|
|
1782
|
+
for (const surface of SURVEY_TRANSLATION_SURFACES) {
|
|
1783
|
+
const targetSurface = targetTranslations?.[surface];
|
|
1784
|
+
for (const [contentKey, sourceContent] of Object.entries(sourceTranslations[surface] ?? {})) addSurface({
|
|
1785
|
+
surface,
|
|
1786
|
+
contentKey,
|
|
1787
|
+
sourceContent,
|
|
1788
|
+
targetContent: targetSurface?.[contentKey]
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
for (const item of survey.surveyItems) for (const [contentKey, sourceContent] of Object.entries(sourceTranslations.itemTranslations?.[item.id] ?? {})) addSurface({
|
|
1792
|
+
itemId: item.id,
|
|
1793
|
+
itemKey: item.key,
|
|
1794
|
+
itemType: item.itemType,
|
|
1795
|
+
contentKey,
|
|
1796
|
+
sourceContent,
|
|
1797
|
+
targetContent: targetTranslations?.itemTranslations?.[item.id]?.[contentKey]
|
|
1798
|
+
});
|
|
1799
|
+
const missingCount = surfaces.filter((surface) => !surface.targetPresent).length;
|
|
1800
|
+
const filteredSurfaces = input.missingOnly ? surfaces.filter((surface) => !surface.targetPresent) : surfaces;
|
|
1801
|
+
const parsedCursor = Number.parseInt(input.cursor ?? "0", 10);
|
|
1802
|
+
const offset = Number.isFinite(parsedCursor) && parsedCursor >= 0 ? parsedCursor : 0;
|
|
1803
|
+
const limit = input.limit ?? 20;
|
|
1804
|
+
const page = filteredSurfaces.slice(offset, offset + limit);
|
|
1805
|
+
const nextOffset = offset + page.length;
|
|
1806
|
+
return {
|
|
1807
|
+
ok: true,
|
|
1808
|
+
result: {
|
|
1809
|
+
sourceLocale,
|
|
1810
|
+
targetLocale,
|
|
1811
|
+
missingOnly: input.missingOnly ?? false,
|
|
1812
|
+
totalSourceSurfaces: surfaces.length,
|
|
1813
|
+
totalAvailable: filteredSurfaces.length,
|
|
1814
|
+
missingCount,
|
|
1815
|
+
returned: page.length,
|
|
1816
|
+
...nextOffset < filteredSurfaces.length ? { nextCursor: String(nextOffset) } : {},
|
|
1817
|
+
listOrdering: { surfaces: "Survey-level translation surfaces first, then item translations in stored survey-item and source content-key order. Cursor pagination preserves this order only while the draft is unchanged; restart without a cursor after mutations." },
|
|
1818
|
+
surfaces: page
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
};
|
|
1639
1822
|
const resolveItemRef = (input, snapshot) => {
|
|
1640
1823
|
if (input.itemRef && input.itemRef !== "selected") return input.itemRef;
|
|
1641
1824
|
return snapshot?.ui.selectedItemId;
|
|
@@ -1717,7 +1900,7 @@ const listAssets = (input, snapshot) => {
|
|
|
1717
1900
|
};
|
|
1718
1901
|
const surveyInspectTool = createTool({
|
|
1719
1902
|
id: TOOL_ID$3,
|
|
1720
|
-
description: "Inspect the current request-scoped survey draft through one compact interface: current context, item search, item details, image assets with explicit asset IDs and usages, or focused raw JSON. At turn start the draft equals the live snapshot; successful same-turn edits appear immediately.",
|
|
1903
|
+
description: "Inspect the current request-scoped survey draft through one compact interface: current context, item search, item details, paged source/target localization surfaces, image assets with explicit asset IDs and usages, or focused raw JSON. At turn start the draft equals the live snapshot; successful same-turn edits appear immediately.",
|
|
1721
1904
|
inputSchema: inputSchema$3,
|
|
1722
1905
|
outputSchema: outputSchema$2,
|
|
1723
1906
|
mcp: { annotations: {
|
|
@@ -1792,6 +1975,27 @@ const surveyInspectTool = createTool({
|
|
|
1792
1975
|
result
|
|
1793
1976
|
};
|
|
1794
1977
|
}
|
|
1978
|
+
if (input.action === "localization") {
|
|
1979
|
+
if (!input.targetLocale) return {
|
|
1980
|
+
ok: false,
|
|
1981
|
+
action: input.action,
|
|
1982
|
+
reason: "Localization inspection requires a targetLocale.",
|
|
1983
|
+
modelSummary: "Localization inspection requires a targetLocale."
|
|
1984
|
+
};
|
|
1985
|
+
const localization = listLocalizationSurfaces(input, snapshot, input.targetLocale);
|
|
1986
|
+
if (!localization.ok) return {
|
|
1987
|
+
ok: false,
|
|
1988
|
+
action: input.action,
|
|
1989
|
+
reason: localization.reason,
|
|
1990
|
+
modelSummary: localization.reason
|
|
1991
|
+
};
|
|
1992
|
+
return {
|
|
1993
|
+
ok: true,
|
|
1994
|
+
action: input.action,
|
|
1995
|
+
modelSummary: stringifyForModel(localization.result),
|
|
1996
|
+
result: localization.result
|
|
1997
|
+
};
|
|
1998
|
+
}
|
|
1795
1999
|
if (input.action === "assets") {
|
|
1796
2000
|
const result = listAssets(input, snapshot);
|
|
1797
2001
|
return {
|
|
@@ -1801,16 +2005,34 @@ const surveyInspectTool = createTool({
|
|
|
1801
2005
|
result
|
|
1802
2006
|
};
|
|
1803
2007
|
}
|
|
1804
|
-
const itemId = resolveItemRef(input, snapshot);
|
|
2008
|
+
const itemId = input.itemRef ? resolveItemRef(input, snapshot) : void 0;
|
|
1805
2009
|
const itemIdentifiers = itemId ? [itemId] : void 0;
|
|
1806
|
-
const
|
|
1807
|
-
|
|
2010
|
+
const requestedPaths = itemIdentifiers ? void 0 : input.paths;
|
|
2011
|
+
const boundedPaths = requestedPaths?.slice(0, MAX_RAW_JSON_PATHS_PER_RESULT);
|
|
2012
|
+
const rawResult = unwrapToolOutput(await runTool(surveyGetRawSurveyTool, {
|
|
2013
|
+
paths: boundedPaths,
|
|
1808
2014
|
itemIdentifiers
|
|
1809
2015
|
}, context));
|
|
2016
|
+
const ignoredPathCount = itemIdentifiers ? input.paths?.length ?? 0 : 0;
|
|
2017
|
+
const omittedPathCount = Math.max(0, (requestedPaths?.length ?? 0) - (boundedPaths?.length ?? 0));
|
|
2018
|
+
const requestCoverage = ignoredPathCount > 0 || omittedPathCount > 0 ? {
|
|
2019
|
+
precedence: itemIdentifiers ? "itemRef was resolved and inspected; explicit paths were ignored." : "Explicit paths were inspected in request order.",
|
|
2020
|
+
requestedPathCount: input.paths?.length ?? 0,
|
|
2021
|
+
inspectedPathCount: boundedPaths?.length ?? 0,
|
|
2022
|
+
ignoredPathCount,
|
|
2023
|
+
omittedPathCount,
|
|
2024
|
+
...omittedPathCount > 0 ? { nextPaths: requestedPaths?.slice(MAX_RAW_JSON_PATHS_PER_RESULT, MAX_RAW_JSON_PATHS_PER_RESULT * 2) } : {},
|
|
2025
|
+
recovery: itemIdentifiers ? "Use a separate raw-json call without itemRef if the explicit paths are still needed." : "Retry the returned nextPaths in a separate raw-json call if they are still needed."
|
|
2026
|
+
} : void 0;
|
|
2027
|
+
const result = requestCoverage && isRecord(rawResult) ? {
|
|
2028
|
+
...rawResult,
|
|
2029
|
+
requestCoverage
|
|
2030
|
+
} : rawResult;
|
|
2031
|
+
const modelSummary = [requestCoverage ? `Raw JSON request normalized instead of rejected: ${JSON.stringify(requestCoverage)}` : void 0, stringifyForModel(result)].filter((value) => Boolean(value)).join("\n");
|
|
1810
2032
|
return {
|
|
1811
2033
|
ok: true,
|
|
1812
2034
|
action: input.action,
|
|
1813
|
-
modelSummary
|
|
2035
|
+
modelSummary,
|
|
1814
2036
|
result
|
|
1815
2037
|
};
|
|
1816
2038
|
},
|
|
@@ -1821,13 +2043,31 @@ const surveyInspectTool = createTool({
|
|
|
1821
2043
|
const TOOL_ID$2 = "survey_attachment";
|
|
1822
2044
|
const surveyAttachmentTool = createTool({
|
|
1823
2045
|
id: TOOL_ID$2,
|
|
1824
|
-
description: "Attach only the stored PDFs or images needed for the current task to the next native model request.
|
|
1825
|
-
inputSchema: z.object({
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
2046
|
+
description: "Attach only the stored PDFs or images needed for the current task to the next native model request. For source continuation, use this before conversational recall and provide a page or section focus when known. The original file remains authoritative.",
|
|
2047
|
+
inputSchema: z.object({
|
|
2048
|
+
documentIds: z.array(z.string().min(1)).min(1).max(4).optional().describe("Stored attachment IDs to load completely when no page/section focus is needed."),
|
|
2049
|
+
documentRequests: z.array(z.object({
|
|
2050
|
+
documentId: z.string().min(1),
|
|
2051
|
+
pages: z.object({
|
|
2052
|
+
start: z.number().int().min(1).max(1e5),
|
|
2053
|
+
end: z.number().int().min(1).max(1e5)
|
|
2054
|
+
}).optional().describe("One-based inclusive PDF page range to prioritize."),
|
|
2055
|
+
focus: z.string().min(1).max(300).optional().describe("Short section, question range, or fact to prioritize in the original file.")
|
|
2056
|
+
})).min(1).max(4).optional().describe("Stored attachments with an optional bounded reading focus.")
|
|
2057
|
+
}),
|
|
2058
|
+
outputSchema: z.object({
|
|
2059
|
+
loaded: z.array(z.object({
|
|
2060
|
+
id: z.string(),
|
|
2061
|
+
filename: z.string(),
|
|
2062
|
+
mediaType: z.string(),
|
|
2063
|
+
pages: z.object({
|
|
2064
|
+
start: z.number().int(),
|
|
2065
|
+
end: z.number().int()
|
|
2066
|
+
}).optional(),
|
|
2067
|
+
focus: z.string().optional()
|
|
2068
|
+
})),
|
|
2069
|
+
warnings: z.array(z.string()).optional()
|
|
2070
|
+
}),
|
|
1831
2071
|
mcp: { annotations: {
|
|
1832
2072
|
title: "Load chat attachment",
|
|
1833
2073
|
readOnlyHint: true,
|
|
@@ -1838,35 +2078,121 @@ const surveyAttachmentTool = createTool({
|
|
|
1838
2078
|
execute: async (inputData, context) => {
|
|
1839
2079
|
const access = (context?.requestContext)?.get("attachmentAccess");
|
|
1840
2080
|
if (!access) return { loaded: [] };
|
|
1841
|
-
const
|
|
2081
|
+
const warnings = [];
|
|
2082
|
+
const requests = /* @__PURE__ */ new Map();
|
|
2083
|
+
for (const documentId of inputData.documentIds ?? []) requests.set(documentId, {});
|
|
2084
|
+
for (const request of inputData.documentRequests ?? []) {
|
|
2085
|
+
if (request.pages && request.pages.end < request.pages.start) {
|
|
2086
|
+
warnings.push(`Ignored invalid page range ${request.pages.start}-${request.pages.end} for ${request.documentId}.`);
|
|
2087
|
+
requests.set(request.documentId, { ...request.focus ? { focus: request.focus } : {} });
|
|
2088
|
+
continue;
|
|
2089
|
+
}
|
|
2090
|
+
requests.set(request.documentId, {
|
|
2091
|
+
...request.pages ? { pages: request.pages } : {},
|
|
2092
|
+
...request.focus ? { focus: request.focus } : {}
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
const requestedIds = [...requests.keys()];
|
|
1842
2096
|
const authorized = access.documents.filter((document) => requestedIds.includes(document.id));
|
|
1843
2097
|
const attachments = await access.load(authorized.map((document) => document.id));
|
|
1844
2098
|
access.selectedAttachments.splice(0, access.selectedAttachments.length, ...attachments);
|
|
1845
|
-
return {
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2099
|
+
return {
|
|
2100
|
+
loaded: authorized.map((document) => {
|
|
2101
|
+
const request = requests.get(document.id);
|
|
2102
|
+
const pages = document.mediaType === "application/pdf" ? request?.pages : void 0;
|
|
2103
|
+
if (request?.pages && !pages) warnings.push(`Ignored a PDF page focus for non-PDF attachment ${document.name}.`);
|
|
2104
|
+
return {
|
|
2105
|
+
id: document.id,
|
|
2106
|
+
filename: document.name,
|
|
2107
|
+
mediaType: document.mediaType,
|
|
2108
|
+
...pages ? { pages } : {},
|
|
2109
|
+
...request?.focus ? { focus: request.focus } : {}
|
|
2110
|
+
};
|
|
2111
|
+
}),
|
|
2112
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
2113
|
+
};
|
|
1850
2114
|
},
|
|
1851
|
-
toModelOutput: (value) => toTextModelOutput(value, () =>
|
|
2115
|
+
toModelOutput: (value) => toTextModelOutput(value, (output) => {
|
|
2116
|
+
if (output.loaded.length === 0) return [
|
|
2117
|
+
"No authorized stored attachment was loaded. Do not infer source content from conversation memory.",
|
|
2118
|
+
...(output.warnings ?? []).map((warning) => `Warning: ${warning}`),
|
|
2119
|
+
"Inspect the available attachment ids and retry with only the source documents needed for this task."
|
|
2120
|
+
].join("\n");
|
|
2121
|
+
const focuses = output.loaded.map((document) => {
|
|
2122
|
+
const details = [document.pages ? `prioritize one-based pages ${document.pages.start}-${document.pages.end}` : void 0, document.focus ? `focus: ${document.focus}` : void 0].filter(Boolean);
|
|
2123
|
+
return details.length > 0 ? `- ${document.filename}: ${details.join("; ")}` : void 0;
|
|
2124
|
+
}).filter((line) => Boolean(line));
|
|
2125
|
+
return [
|
|
2126
|
+
"The selected complete original attachments are included in this model input. Read them directly now and continue the user's task. Conversation memory is not a lossless source.",
|
|
2127
|
+
focuses.length > 0 ? `Requested reading focus (the complete original remains authoritative):\n${focuses.join("\n")}` : void 0,
|
|
2128
|
+
...(output.warnings ?? []).map((warning) => `Warning: ${warning}`),
|
|
2129
|
+
"Do not claim that successfully loaded content is unavailable or ask the user to paste extracted text."
|
|
2130
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
2131
|
+
})
|
|
1852
2132
|
});
|
|
1853
2133
|
//#endregion
|
|
1854
2134
|
//#region src/server/tools/survey-audit-tool.ts
|
|
1855
2135
|
const TOOL_ID$1 = "survey_audit";
|
|
2136
|
+
const inputSchema$1 = z.object({
|
|
2137
|
+
sourceLocale: z.string().min(1).optional().describe("Locale treated as the source when checking translation completeness."),
|
|
2138
|
+
targetLocales: z.array(z.string().min(1)).max(20).optional(),
|
|
2139
|
+
maxFindings: z.number().int().min(1).max(300).default(120).optional(),
|
|
2140
|
+
reason: z.string().max(500).optional()
|
|
2141
|
+
});
|
|
2142
|
+
const outputSchema = z.object({
|
|
2143
|
+
ok: z.boolean(),
|
|
2144
|
+
reason: z.string().optional(),
|
|
2145
|
+
report: z.unknown().optional()
|
|
2146
|
+
});
|
|
2147
|
+
const MAX_AUDIT_MODEL_GROUPS = 16;
|
|
2148
|
+
const MAX_AUDIT_MODEL_EXAMPLES = 12;
|
|
2149
|
+
const MAX_AUDIT_MESSAGE_CHARACTERS = 300;
|
|
2150
|
+
const previewAuditMessage = (message) => {
|
|
2151
|
+
const characters = [...message];
|
|
2152
|
+
if (characters.length <= MAX_AUDIT_MESSAGE_CHARACTERS) return message;
|
|
2153
|
+
return `${characters.slice(0, MAX_AUDIT_MESSAGE_CHARACTERS).join("")}… [${characters.length} characters total]`;
|
|
2154
|
+
};
|
|
2155
|
+
const formatAuditForModel = (output) => {
|
|
2156
|
+
if (!output.ok || !output.report || typeof output.report !== "object") return output.reason ?? "The deterministic survey audit could not be completed.";
|
|
2157
|
+
const report = output.report;
|
|
2158
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2159
|
+
for (const finding of report.findings) {
|
|
2160
|
+
const key = `${finding.severity}\u0000${finding.category}\u0000${finding.code}`;
|
|
2161
|
+
const group = groups.get(key) ?? {
|
|
2162
|
+
category: finding.category,
|
|
2163
|
+
code: finding.code,
|
|
2164
|
+
count: 0,
|
|
2165
|
+
severity: finding.severity
|
|
2166
|
+
};
|
|
2167
|
+
group.count += 1;
|
|
2168
|
+
groups.set(key, group);
|
|
2169
|
+
}
|
|
2170
|
+
const groupedFindings = [...groups.values()].sort((left, right) => right.count - left.count || left.severity.localeCompare(right.severity) || left.code.localeCompare(right.code));
|
|
2171
|
+
const shownGroups = groupedFindings.slice(0, MAX_AUDIT_MODEL_GROUPS);
|
|
2172
|
+
const examples = report.findings.slice(0, MAX_AUDIT_MODEL_EXAMPLES);
|
|
2173
|
+
return [
|
|
2174
|
+
`Deterministic survey audit: ${report.findingCount} finding${report.findingCount === 1 ? "" : "s"} (errors=${report.summary.error}, warnings=${report.summary.warning}, info=${report.summary.info}).`,
|
|
2175
|
+
`Finding coverage returned by the audit: ${report.findings.length}/${report.findingCount}${report.truncated ? " (bounded)" : ""}.`,
|
|
2176
|
+
`Metrics: ${JSON.stringify(report.metrics)}.`,
|
|
2177
|
+
shownGroups.length > 0 ? `Finding groups (${shownGroups.length}/${groupedFindings.length} shown):\n${shownGroups.map((group) => `- ${group.severity}/${group.category}/${group.code}: ${group.count} returned finding${group.count === 1 ? "" : "s"}`).join("\n")}` : "Finding groups: none.",
|
|
2178
|
+
examples.length > 0 ? `Ordered examples (${examples.length}/${report.findings.length} returned findings shown):\n${examples.map((finding) => {
|
|
2179
|
+
const location = [
|
|
2180
|
+
finding.itemId,
|
|
2181
|
+
finding.locale,
|
|
2182
|
+
finding.contentKey
|
|
2183
|
+
].filter(Boolean).join(":");
|
|
2184
|
+
return `- ${finding.code}${location ? ` (${location})` : ""}: ${previewAuditMessage(finding.message)}`;
|
|
2185
|
+
}).join("\n")}` : void 0,
|
|
2186
|
+
report.qualityReviewPrinciples.length > 0 ? `Qualitative review rubric:\n${report.qualityReviewPrinciples.map((principle) => `- ${principle.id}: ${principle.prompt}`).join("\n")}` : void 0,
|
|
2187
|
+
report.note,
|
|
2188
|
+
"This audit checks the current survey deterministically. It does not compare the draft with an attached source document, so a clean audit does not establish source fidelity or completeness."
|
|
2189
|
+
].filter((line) => Boolean(line)).join("\n\n");
|
|
2190
|
+
};
|
|
1856
2191
|
const surveyAuditTool = createTool({
|
|
1857
2192
|
id: TOOL_ID$1,
|
|
1858
2193
|
description: "Audit the current survey for deterministic structural, content, localization, response, and asset issues, and return a research-informed questionnaire-quality review rubric for qualitative critique. This is read-only and is not psychometric validation.",
|
|
1859
|
-
inputSchema:
|
|
1860
|
-
|
|
1861
|
-
targetLocales: z.array(z.string().min(1)).max(20).optional(),
|
|
1862
|
-
maxFindings: z.number().int().min(1).max(300).default(120).optional(),
|
|
1863
|
-
reason: z.string().max(500).optional()
|
|
1864
|
-
}),
|
|
1865
|
-
outputSchema: z.object({
|
|
1866
|
-
ok: z.boolean(),
|
|
1867
|
-
reason: z.string().optional(),
|
|
1868
|
-
report: z.unknown().optional()
|
|
1869
|
-
}),
|
|
2194
|
+
inputSchema: inputSchema$1,
|
|
2195
|
+
outputSchema,
|
|
1870
2196
|
mcp: { annotations: {
|
|
1871
2197
|
title: "Audit survey",
|
|
1872
2198
|
readOnlyHint: true,
|
|
@@ -1885,7 +2211,7 @@ const surveyAuditTool = createTool({
|
|
|
1885
2211
|
report: auditSurvey(snapshot, input)
|
|
1886
2212
|
};
|
|
1887
2213
|
},
|
|
1888
|
-
toModelOutput: (value) => toTextModelOutput(value,
|
|
2214
|
+
toModelOutput: (value) => toTextModelOutput(value, formatAuditForModel)
|
|
1889
2215
|
});
|
|
1890
2216
|
//#endregion
|
|
1891
2217
|
//#region src/server/tools/survey-asset-tool.ts
|
|
@@ -2089,4 +2415,4 @@ const surveyAssistantTools = Object.freeze({
|
|
|
2089
2415
|
//#endregion
|
|
2090
2416
|
export { surveyAuditTool as i, surveyAssistantTools as n, surveyAssetTool as r, SURVEY_ASSISTANT_TOOL_IDS as t };
|
|
2091
2417
|
|
|
2092
|
-
//# sourceMappingURL=tools-
|
|
2418
|
+
//# sourceMappingURL=tools-Dg9HZrYU.mjs.map
|