@case-framework/survey-assistant 0.1.0 → 0.2.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/README.md +71 -11
- package/dist/{authoring-references-X6uRaWuf.mjs → authoring-references-DYuOAdVx.mjs} +26 -2
- package/dist/authoring-references-DYuOAdVx.mjs.map +1 -0
- package/dist/{capabilities-B6tvE7fK.mjs → capabilities-DZ0a_o2y.mjs} +2 -2
- package/dist/{capabilities-B6tvE7fK.mjs.map → capabilities-DZ0a_o2y.mjs.map} +1 -1
- package/dist/{capabilities-DvSKtjAw.d.mts → capabilities-DlC1l6qy.d.mts} +4 -1
- package/dist/capabilities-DlC1l6qy.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 +6 -3
- package/dist/capabilities-default.mjs.map +1 -1
- package/dist/{constants-Jw0k8ojS.d.mts → constants-56jf_4ls.d.mts} +36 -9
- package/dist/constants-56jf_4ls.d.mts.map +1 -0
- package/dist/{controller-proxy-BRDusFiO.d.mts → controller-proxy-2VH0b_5E.d.mts} +29 -4
- package/dist/controller-proxy-2VH0b_5E.d.mts.map +1 -0
- package/dist/{controller-proxy-Duxo2IFE.mjs → controller-proxy-ClsY4lFI.mjs} +74 -5
- package/dist/controller-proxy-ClsY4lFI.mjs.map +1 -0
- package/dist/{digest-BsoVq49o.d.mts → digest-BvXpeWcR.d.mts} +2 -2
- package/dist/{digest-BsoVq49o.d.mts.map → digest-BvXpeWcR.d.mts.map} +1 -1
- package/dist/digest.d.mts +1 -1
- package/dist/{engine-sPvuixWg.mjs → engine-DQrCO_ur.mjs} +392 -50
- package/dist/engine-DQrCO_ur.mjs.map +1 -0
- package/dist/engine.d.mts +2 -2
- package/dist/engine.mjs +2 -2
- package/dist/{index-MpEMQzTm.d.mts → index-B_x2IYi7.d.mts} +5 -1
- package/dist/index-B_x2IYi7.d.mts.map +1 -0
- package/dist/{index-BWNHkpkh.d.mts → index-C_x686M7.d.mts} +27 -5
- package/dist/index-C_x686M7.d.mts.map +1 -0
- package/dist/{index-TFtvBiSQ.d.mts → index-DVxVyhAu.d.mts} +31 -9
- package/dist/index-DVxVyhAu.d.mts.map +1 -0
- package/dist/{index-CUqbBjkc.d.mts → index-DZ6KBwVR.d.mts} +16 -3
- package/dist/index-DZ6KBwVR.d.mts.map +1 -0
- package/dist/{memory-thread-repository-CJkkVE2-.mjs → memory-thread-repository-Cm1BJyRw.mjs} +110 -41
- package/dist/memory-thread-repository-Cm1BJyRw.mjs.map +1 -0
- package/dist/{protocol-DV0ka9WT.mjs → protocol-7EEgcYja.mjs} +70 -97
- package/dist/protocol-7EEgcYja.mjs.map +1 -0
- package/dist/protocol.d.mts +3 -3
- package/dist/protocol.mjs +2 -2
- package/dist/{react-VuYe-cPh.mjs → react-B_5smfiK.mjs} +145 -38
- package/dist/react-B_5smfiK.mjs.map +1 -0
- package/dist/react-integration.d.mts +2 -2
- package/dist/react-integration.mjs +2 -2
- package/dist/react.d.mts +3 -3
- package/dist/react.mjs +3 -3
- package/dist/references/assistant-operations.md +6 -0
- package/dist/references/core-rules.md +6 -0
- package/dist/references/embedded-forms.md +21 -14
- package/dist/references/expressions.md +3 -0
- package/dist/references/item-types.md +37 -10
- package/dist/references/source-material-surveys.md +9 -1
- package/dist/references/survey-data-model.md +13 -0
- package/dist/request-context-BDBw4-Gw.mjs +79 -0
- package/dist/request-context-BDBw4-Gw.mjs.map +1 -0
- package/dist/request-guardrails-h4t6u8mP.mjs +129 -0
- package/dist/request-guardrails-h4t6u8mP.mjs.map +1 -0
- package/dist/server-agent.d.mts +6 -2
- package/dist/server-agent.d.mts.map +1 -1
- package/dist/server-agent.mjs +39 -24
- package/dist/server-agent.mjs.map +1 -1
- package/dist/server-runtime.d.mts +21 -5
- package/dist/server-runtime.d.mts.map +1 -1
- package/dist/server-runtime.mjs +98 -32
- package/dist/server-runtime.mjs.map +1 -1
- package/dist/server-tasks.d.mts +2 -78
- package/dist/server-tasks.mjs +103 -46
- 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 +89 -21
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +136 -5
- package/dist/server.mjs.map +1 -0
- package/dist/storage-postgres.d.mts +12 -2
- package/dist/storage-postgres.d.mts.map +1 -1
- package/dist/storage-postgres.mjs +11 -6
- package/dist/storage-postgres.mjs.map +1 -1
- package/dist/tasks-COQnhSeT.d.mts +140 -0
- package/dist/tasks-COQnhSeT.d.mts.map +1 -0
- package/dist/{thread-documents-DamIq9Od.d.mts → thread-documents-BlxNjc7S.d.mts} +21 -5
- package/dist/thread-documents-BlxNjc7S.d.mts.map +1 -0
- package/dist/{thread-handlers-DpynUc64.d.mts → thread-handlers-l79JBl5m.d.mts} +38 -5
- package/dist/thread-handlers-l79JBl5m.d.mts.map +1 -0
- package/dist/{tools-Hz2p7vyv.mjs → tools-DDXaJ8Za.mjs} +257 -38
- package/dist/tools-DDXaJ8Za.mjs.map +1 -0
- package/dist/ui.d.mts +5 -3
- package/dist/ui.d.mts.map +1 -1
- package/dist/ui.mjs +91 -12
- package/dist/ui.mjs.map +1 -1
- package/docs/integration.md +234 -0
- package/package.json +9 -7
- package/dist/authoring-references-Cy8J-DWt.d.mts +0 -48
- package/dist/authoring-references-Cy8J-DWt.d.mts.map +0 -1
- package/dist/authoring-references-X6uRaWuf.mjs.map +0 -1
- package/dist/capabilities-DvSKtjAw.d.mts.map +0 -1
- package/dist/constants-Jw0k8ojS.d.mts.map +0 -1
- package/dist/controller-proxy-BRDusFiO.d.mts.map +0 -1
- package/dist/controller-proxy-Duxo2IFE.mjs.map +0 -1
- package/dist/engine-sPvuixWg.mjs.map +0 -1
- package/dist/index-BWNHkpkh.d.mts.map +0 -1
- package/dist/index-CUqbBjkc.d.mts.map +0 -1
- package/dist/index-MpEMQzTm.d.mts.map +0 -1
- package/dist/index-TFtvBiSQ.d.mts.map +0 -1
- package/dist/memory-thread-repository-CJkkVE2-.mjs.map +0 -1
- package/dist/protocol-DV0ka9WT.mjs.map +0 -1
- package/dist/react-VuYe-cPh.mjs.map +0 -1
- package/dist/request-context-jcmXT_Q2.mjs +0 -44
- package/dist/request-context-jcmXT_Q2.mjs.map +0 -1
- package/dist/request-guardrails-C59IWnH8.mjs +0 -73
- package/dist/request-guardrails-C59IWnH8.mjs.map +0 -1
- package/dist/server-tasks.d.mts.map +0 -1
- package/dist/thread-documents-DamIq9Od.d.mts.map +0 -1
- package/dist/thread-handlers-DpynUc64.d.mts.map +0 -1
- package/dist/tools-Hz2p7vyv.mjs.map +0 -1
|
@@ -1,12 +1,92 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as getDeterministicCreateItemTypes, o as inspectAssistantItem, s as resolveAssistantCapabilityReference } from "./capabilities-
|
|
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, a as SURVEY_CHANGE_CONTINUATION_MODES, b as buildItemTranslationEntries, d as normalizeSurveyChangeOperations, f as buildExpressionMutationPatches, i as SURVEY_CHANGE_CONTINUATION_DESCRIPTION, j as getRawSurveyItems, k as getKeyIndexEntries, l as createSurveyChangeSet, p as expressionMutationSchema, q as summarizeRawItem, t as auditSurvey, v as buildEmbeddedFormDetails, w as findDirectChildrenByFullKey, y as buildItemConfigDetails } from "./engine-
|
|
4
|
-
import {
|
|
5
|
-
import { n as surveyAuthoringReferences, t as
|
|
1
|
+
import { G as assistantItemTypeManifestSchema, J as SURVEY_OPERATION_KINDS, _t as surveyOperationSchema, u as surveyChangeSetSchema, vt as surveyOperationSchemasByKind } from "./protocol-7EEgcYja.mjs";
|
|
2
|
+
import { a as getDeterministicCreateItemTypes, o as inspectAssistantItem, s as resolveAssistantCapabilityReference } from "./capabilities-DZ0a_o2y.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, a as SURVEY_CHANGE_CONTINUATION_MODES, b as buildItemTranslationEntries, d as normalizeSurveyChangeOperations, f as buildExpressionMutationPatches, i as SURVEY_CHANGE_CONTINUATION_DESCRIPTION, j as getRawSurveyItems, k as getKeyIndexEntries, l as createSurveyChangeSet, p as expressionMutationSchema, q as summarizeRawItem, t as auditSurvey, v as buildEmbeddedFormDetails, w as findDirectChildrenByFullKey, y as buildItemConfigDetails } from "./engine-DQrCO_ur.mjs";
|
|
4
|
+
import { a as requireSurveyAssistantTurnState } from "./request-context-BDBw4-Gw.mjs";
|
|
5
|
+
import { n as surveyAuthoringReferenceTopics, r as surveyAuthoringReferences, t as getBuiltInItemTypeAuthoringReference } from "./authoring-references-DYuOAdVx.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
|
-
import { JsonPatchError, encodeJsonPointerSegment, getAssetUsagesFromContent, getValueAtJsonPointer } from "@case-framework/survey-core";
|
|
7
|
+
import { JsonPatchError, SURVEY_EDITOR_ITEM_COLORS, encodeJsonPointerSegment, getAssetUsagesFromContent, getValueAtJsonPointer } from "@case-framework/survey-core";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { createTool, isValidationError } from "@mastra/core/tools";
|
|
10
|
+
//#region src/server/operation-contract-reference.ts
|
|
11
|
+
const isSurveyOperationKind = (value) => SURVEY_OPERATION_KINDS.includes(value);
|
|
12
|
+
const SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS = ["compact", "full"];
|
|
13
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
const summarizeLargeSchema = (schema, propertyName) => {
|
|
15
|
+
const description = typeof schema.description === "string" ? schema.description : propertyName ? `Canonical value for "${propertyName}".` : "Canonical value.";
|
|
16
|
+
const type = typeof schema.type === "string" ? schema.type : void 0;
|
|
17
|
+
return {
|
|
18
|
+
...type ? { type } : {},
|
|
19
|
+
description: `${description} The deeply nested schema is omitted from this compact reference; load the dedicated authoring reference when this structured value is needed.`
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const compactJsonSchema = (value, propertyName, depth = 0) => {
|
|
23
|
+
if (Array.isArray(value)) return value.map((entry) => compactJsonSchema(entry, propertyName, depth + 1));
|
|
24
|
+
if (!isRecord$1(value)) return value;
|
|
25
|
+
if (typeof value.$ref === "string") return { description: "Recursive structured value omitted from this compact reference; request full detail only for protocol debugging." };
|
|
26
|
+
if (depth >= 3 && JSON.stringify(value).length > 12e3) return summarizeLargeSchema(value, propertyName);
|
|
27
|
+
const compact = {};
|
|
28
|
+
for (const key of [
|
|
29
|
+
"type",
|
|
30
|
+
"const",
|
|
31
|
+
"enum",
|
|
32
|
+
"description",
|
|
33
|
+
"minimum",
|
|
34
|
+
"maximum",
|
|
35
|
+
"minLength",
|
|
36
|
+
"maxLength",
|
|
37
|
+
"minItems",
|
|
38
|
+
"maxItems",
|
|
39
|
+
"required",
|
|
40
|
+
"additionalProperties"
|
|
41
|
+
]) if (value[key] !== void 0) compact[key] = value[key];
|
|
42
|
+
if (isRecord$1(value.properties)) compact.properties = Object.fromEntries(Object.entries(value.properties).map(([key, schema]) => [key, compactJsonSchema(schema, key, depth + 1)]));
|
|
43
|
+
if (value.items !== void 0) compact.items = compactJsonSchema(value.items, propertyName, depth + 1);
|
|
44
|
+
for (const unionKey of ["oneOf", "anyOf"]) if (Array.isArray(value[unionKey])) compact[unionKey] = value[unionKey].map((entry) => compactJsonSchema(entry, propertyName, depth + 1));
|
|
45
|
+
return compact;
|
|
46
|
+
};
|
|
47
|
+
const formatItemCapabilityProfile = (manifest, kind) => {
|
|
48
|
+
const fixedSurfaces = manifest.contentSurfaces.filter((surface) => !surface.pattern);
|
|
49
|
+
const patternedSurfaces = manifest.contentSurfaces.filter((surface) => surface.pattern);
|
|
50
|
+
const requiredSurfaces = fixedSurfaces.filter((surface) => surface.requiredOnCreate);
|
|
51
|
+
const lines = [
|
|
52
|
+
`## Item capability: \`${manifest.itemType}\``,
|
|
53
|
+
"",
|
|
54
|
+
`${manifest.displayName}: ${manifest.description ?? "No additional description."}`,
|
|
55
|
+
`Creation mode: ${manifest.create}.`,
|
|
56
|
+
manifest.authoring?.configSummary ? `Configuration: ${manifest.authoring.configSummary}` : void 0,
|
|
57
|
+
fixedSurfaces.length > 0 ? `Fixed content surfaces: ${fixedSurfaces.map((surface) => surface.key).join(", ")}.` : "Fixed content surfaces: none.",
|
|
58
|
+
patternedSurfaces.length > 0 ? `Dynamic content surfaces: ${patternedSurfaces.map((surface) => surface.key).join(", ")}.` : void 0,
|
|
59
|
+
kind === "create-item" && requiredSurfaces.length > 0 ? `Required on creation: ${requiredSurfaces.map((surface) => surface.key).join(", ")}.` : void 0,
|
|
60
|
+
manifest.referenceTopics?.length ? `Load a dedicated reference only when needed: ${manifest.referenceTopics.join(", ")}.` : void 0
|
|
61
|
+
].filter((line) => Boolean(line));
|
|
62
|
+
if (kind === "create-item") lines.push("", "Creation scope: put the complete initial item structure, configuration, and visible translations in this create-item operation. Operations that edit an item by itemId target items already present in the immutable live snapshot; do not create an empty item and then target its new id with option or field editing operations in the same response.");
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
};
|
|
65
|
+
const formatSurveyOperationContractReference = (kind, options = {}) => {
|
|
66
|
+
const { $schema: _schemaVersion, ...contract } = z.toJSONSchema(surveyOperationSchemasByKind[kind], {
|
|
67
|
+
io: "input",
|
|
68
|
+
reused: "inline",
|
|
69
|
+
unrepresentable: "any"
|
|
70
|
+
});
|
|
71
|
+
const detail = options.detail ?? "compact";
|
|
72
|
+
const renderedContract = detail === "full" ? contract : compactJsonSchema(contract);
|
|
73
|
+
const itemCapability = options.itemCapability;
|
|
74
|
+
return [
|
|
75
|
+
`# \`${kind}\` operation contract`,
|
|
76
|
+
"",
|
|
77
|
+
"This JSON Schema is generated from the structural validator used by `survey_change`; it is",
|
|
78
|
+
"the canonical field shape. Cross-field and snapshot-dependent rules are enforced when the",
|
|
79
|
+
"proposal is validated. The tool may normalize limited schema-near shorthand, but prefer this",
|
|
80
|
+
"canonical form.",
|
|
81
|
+
detail === "compact" ? "This compact view preserves the operation structure while omitting deeply nested value schemas. Request detail \"full\" only for protocol debugging; load a focused rich-text, expression, form, or item-type reference for authoring guidance." : "This full view is intended for protocol debugging and may be large.",
|
|
82
|
+
"",
|
|
83
|
+
"```json",
|
|
84
|
+
JSON.stringify(renderedContract, null, 2),
|
|
85
|
+
"```",
|
|
86
|
+
...itemCapability ? ["", formatItemCapabilityProfile(itemCapability, kind)] : []
|
|
87
|
+
].join("\n");
|
|
88
|
+
};
|
|
89
|
+
//#endregion
|
|
10
90
|
//#region src/server/tools/tool-model-output.ts
|
|
11
91
|
const FALLBACK_MODEL_TEXT = "The tool returned no model-readable output. Review the tool arguments and retry with valid values.";
|
|
12
92
|
const unwrapToolOutput$1 = (value) => value && typeof value === "object" && "output" in value && value.output !== void 0 ? value.output : value;
|
|
@@ -32,16 +112,20 @@ const TOOL_ID$10 = "survey_authoring_reference";
|
|
|
32
112
|
const topicSchema = z.string().min(1).max(120);
|
|
33
113
|
const surveyAuthoringReferenceTool = createTool({
|
|
34
114
|
id: TOOL_ID$10,
|
|
35
|
-
description: "Load one narrow CASE
|
|
115
|
+
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.",
|
|
36
116
|
inputSchema: z.object({
|
|
37
117
|
topic: topicSchema.describe("The narrow authoring reference to load."),
|
|
38
|
-
itemType: z.string().min(1).max(120).optional().describe("Installed
|
|
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."),
|
|
39
121
|
reason: z.string().max(500).optional().describe("Short reason this reference is needed.")
|
|
40
122
|
}),
|
|
41
123
|
outputSchema: z.object({
|
|
42
124
|
ok: z.boolean(),
|
|
43
125
|
topic: topicSchema,
|
|
44
126
|
itemType: z.string().optional(),
|
|
127
|
+
operationKind: z.string().optional(),
|
|
128
|
+
detail: z.enum(SURVEY_OPERATION_CONTRACT_DETAIL_LEVELS).optional(),
|
|
45
129
|
title: z.string(),
|
|
46
130
|
content: z.string()
|
|
47
131
|
}),
|
|
@@ -53,22 +137,75 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
53
137
|
openWorldHint: false
|
|
54
138
|
} },
|
|
55
139
|
execute: async (inputData, context) => {
|
|
56
|
-
const
|
|
140
|
+
const contractDetail = inputData.detail ?? "compact";
|
|
57
141
|
const engineContext = context?.requestContext?.get("engineContext");
|
|
142
|
+
const itemCapability = inputData.itemType ? engineContext?.trustedCapabilities?.byItemType.get(inputData.itemType)?.manifest ?? engineContext?.capabilities.itemTypes.find((entry) => entry.itemType === inputData.itemType) : void 0;
|
|
143
|
+
if (inputData.operationKind && inputData.topic !== "assistant-operations") return {
|
|
144
|
+
ok: false,
|
|
145
|
+
topic: inputData.topic,
|
|
146
|
+
itemType: inputData.itemType,
|
|
147
|
+
operationKind: inputData.operationKind,
|
|
148
|
+
title: "Operation contract unavailable",
|
|
149
|
+
content: "operationKind is supported only with topic assistant-operations."
|
|
150
|
+
};
|
|
151
|
+
if (inputData.operationKind) {
|
|
152
|
+
if (!isSurveyOperationKind(inputData.operationKind)) return {
|
|
153
|
+
ok: false,
|
|
154
|
+
topic: inputData.topic,
|
|
155
|
+
operationKind: inputData.operationKind,
|
|
156
|
+
detail: contractDetail,
|
|
157
|
+
title: "Operation contract unavailable",
|
|
158
|
+
content: `No built-in survey_change operation named "${inputData.operationKind}" is available.`
|
|
159
|
+
};
|
|
160
|
+
if (inputData.itemType && !itemCapability) return {
|
|
161
|
+
ok: false,
|
|
162
|
+
topic: inputData.topic,
|
|
163
|
+
itemType: inputData.itemType,
|
|
164
|
+
operationKind: inputData.operationKind,
|
|
165
|
+
detail: contractDetail,
|
|
166
|
+
title: "Item capability unavailable",
|
|
167
|
+
content: `No installed survey item capability named "${inputData.itemType}" is available.`
|
|
168
|
+
};
|
|
169
|
+
if (itemCapability && !itemCapability.supportedOperations.includes(inputData.operationKind)) return {
|
|
170
|
+
ok: false,
|
|
171
|
+
topic: inputData.topic,
|
|
172
|
+
itemType: inputData.itemType,
|
|
173
|
+
operationKind: inputData.operationKind,
|
|
174
|
+
detail: contractDetail,
|
|
175
|
+
title: "Operation unsupported for item type",
|
|
176
|
+
content: `Item type "${itemCapability.itemType}" does not support survey_change operation "${inputData.operationKind}".`
|
|
177
|
+
};
|
|
178
|
+
return {
|
|
179
|
+
ok: true,
|
|
180
|
+
topic: inputData.topic,
|
|
181
|
+
itemType: inputData.itemType,
|
|
182
|
+
operationKind: inputData.operationKind,
|
|
183
|
+
detail: contractDetail,
|
|
184
|
+
title: itemCapability ? `${inputData.operationKind} for ${itemCapability.displayName}` : `${inputData.operationKind} operation contract`,
|
|
185
|
+
content: formatSurveyOperationContractReference(inputData.operationKind, {
|
|
186
|
+
detail: contractDetail,
|
|
187
|
+
itemCapability
|
|
188
|
+
})
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const builtInEntry = surveyAuthoringReferenceTopics.includes(inputData.topic) ? surveyAuthoringReferences[inputData.topic] : void 0;
|
|
58
192
|
const capability = inputData.itemType ? engineContext?.trustedCapabilities?.byItemType.get(inputData.itemType) : void 0;
|
|
59
193
|
const capabilityReference = inputData.itemType ? resolveAssistantCapabilityReference({
|
|
60
194
|
capabilities: engineContext?.trustedCapabilities,
|
|
61
195
|
itemType: inputData.itemType,
|
|
62
196
|
topic: inputData.topic
|
|
63
197
|
}) : void 0;
|
|
64
|
-
const
|
|
198
|
+
const focusedBuiltInItemTypeReference = inputData.topic === "item-types" && inputData.itemType ? getBuiltInItemTypeAuthoringReference(inputData.itemType) : void 0;
|
|
199
|
+
const capabilityEntry = capabilityReference ? {
|
|
65
200
|
title: capabilityReference.title ?? `${capability?.manifest.displayName} authoring`,
|
|
66
201
|
content: capabilityReference.markdown
|
|
67
|
-
} :
|
|
202
|
+
} : void 0;
|
|
203
|
+
const entry = focusedBuiltInItemTypeReference ?? capabilityEntry ?? builtInEntry;
|
|
68
204
|
if (!entry) return {
|
|
69
205
|
ok: false,
|
|
70
206
|
topic: inputData.topic,
|
|
71
207
|
itemType: inputData.itemType,
|
|
208
|
+
operationKind: inputData.operationKind,
|
|
72
209
|
title: "Reference unavailable",
|
|
73
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.`
|
|
74
211
|
};
|
|
@@ -76,6 +213,7 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
76
213
|
ok: true,
|
|
77
214
|
topic: inputData.topic,
|
|
78
215
|
itemType: inputData.itemType,
|
|
216
|
+
operationKind: inputData.operationKind,
|
|
79
217
|
title: entry.title,
|
|
80
218
|
content: entry.content
|
|
81
219
|
};
|
|
@@ -85,14 +223,30 @@ const surveyAuthoringReferenceTool = createTool({
|
|
|
85
223
|
//#endregion
|
|
86
224
|
//#region src/server/tools/survey-change-tool.ts
|
|
87
225
|
const TOOL_ID$9 = "survey_change";
|
|
226
|
+
const OPERATIONS_DESCRIPTION = [
|
|
227
|
+
"Typed survey operation objects to validate and package as one undoable change. Every object uses discriminator \"kind\", never \"type\".",
|
|
228
|
+
"For an unfamiliar canonical shape, load survey_authoring_reference with topic \"assistant-operations\" and operationKind; it returns only that operation schema, generated from the validator.",
|
|
229
|
+
"Any translations owned by an operation must be inside that same operation object. Never put translations beside the survey_change operations array.",
|
|
230
|
+
"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
|
+
"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
|
+
"Item-editing operations target items already present in the immutable live snapshot. For a new item, put its complete initial options, fields, config, translations, and embedded expressions directly in create-item; do not create it empty and target its new id later in the response.",
|
|
233
|
+
"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.",
|
|
234
|
+
"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.",
|
|
235
|
+
`Use update-item-color only with a supported swatch. ${`Allowed editor item-color swatches: ${SURVEY_EDITOR_ITEM_COLORS.join(", ")}. Use one of these exact values for update-item-color; do not wait for validation feedback to choose a swatch.`}`,
|
|
236
|
+
"Use patch-item-config with itemId and plural patches whose JSON Pointer paths are relative to that item config root.",
|
|
237
|
+
"Use update-placed-image only for an image already present in the immutable snapshot. For a new item, embed the complete image block directly in create-item translations.",
|
|
238
|
+
"When deleting referenced images and assets, include every reference-removal operation and remove-image-asset last in the same operations array.",
|
|
239
|
+
"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.",
|
|
240
|
+
"Keep proposals bounded; split oversized work into independent complete change calls."
|
|
241
|
+
].join(" ");
|
|
88
242
|
const inputSchema$9 = z.object({
|
|
89
243
|
intent: z.string().min(1).max(500).describe("The concrete survey change requested by the user."),
|
|
90
244
|
summary: z.string().min(1).max(500).describe("Short user-facing summary of the intended survey change."),
|
|
91
|
-
operations: z.array(z.unknown()).min(1).max(200).describe(
|
|
245
|
+
operations: z.array(z.unknown()).min(1).max(200).describe(OPERATIONS_DESCRIPTION),
|
|
92
246
|
continuationMode: z.enum(SURVEY_CHANGE_CONTINUATION_MODES).nullish().transform((value) => value ?? void 0).describe(`${SURVEY_CHANGE_CONTINUATION_DESCRIPTION} Omit this field instead of sending null.`),
|
|
93
247
|
inspectedContext: z.array(z.string().max(240)).max(20).nullish().transform((value) => value ?? void 0).describe("Optional item ids, paths, or references inspected before proposing this change."),
|
|
94
248
|
notes: z.string().max(1e3).nullish().transform((value) => value ?? void 0).describe("Optional implementation notes for validation/debugging; not shown as persisted survey content.")
|
|
95
|
-
});
|
|
249
|
+
}).strict();
|
|
96
250
|
const rejectedOperationParseEvent = ({ issueText, summary, turnId }) => ({
|
|
97
251
|
protocolVersion: 1,
|
|
98
252
|
id: randomUUID(),
|
|
@@ -150,7 +304,9 @@ const summarizeValidation = (event) => {
|
|
|
150
304
|
const lines = [`${event.status === "validated" ? "Validated" : "Rejected"} survey change: ${event.summary}`, `Change id: ${event.id}`];
|
|
151
305
|
if (event.operations.length > 0) lines.push(`Operations: ${event.operations.map((operation) => operation.kind).join(", ")}`);
|
|
152
306
|
if (event.status === "rejected") {
|
|
153
|
-
lines.push("Apply status: this
|
|
307
|
+
lines.push("Apply status: blocked; this candidate is not authorized.");
|
|
308
|
+
if (event.recovery?.requiredContinuationMode) lines.push(`Required recovery: resubmit the complete intended proposal with continuationMode "${event.recovery.requiredContinuationMode}". No survey change from this turn can be authorized until that replacement validates.`);
|
|
309
|
+
else if (event.recovery) lines.push(`Required recovery: resubmit the complete proposal with an explicit continuationMode (${event.recovery.allowedContinuationModes.join(" or ")}).`);
|
|
154
310
|
if (event.operations.length > 0) {
|
|
155
311
|
const checklist = event.operations.slice(0, 24).map(describeOperationTarget);
|
|
156
312
|
lines.push(`Unapplied target sample (${checklist.length} of ${event.operations.length}):\n${checklist.map((target) => `- ${target}`).join("\n")}`);
|
|
@@ -168,8 +324,6 @@ const summarizeValidation = (event) => {
|
|
|
168
324
|
const issueCodes = new Set(event.validation.issues.map((issue) => issue.code));
|
|
169
325
|
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 the complete create-item proposal with continuationMode \"replace\". 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.");
|
|
170
326
|
if (issueCodes.has("too-many-operations")) lines.push("Recovery hint: keep the same inspected survey context and immediately split these edits into smaller survey_change calls. Use continuationMode \"replace\" on the first repaired chunk, then \"append\" on every later independent chunk. Do not claim that a new snapshot is needed unless a tool explicitly reported a missing snapshot.");
|
|
171
|
-
if (issueCodes.has("change-mode-required")) lines.push("Recovery hint: retry the complete intended proposal with continuationMode \"append\" for independent additional work or \"replace\" for a correction. Nothing from the ambiguous sequence is currently authorized.");
|
|
172
|
-
if (issueCodes.has("change-mode-repair-required")) lines.push("Recovery hint: the turn remains blocked. Retry the complete intended proposal with continuationMode \"replace\". Only a validated replacement clears the block; after that, use \"append\" for later independent chunks.");
|
|
173
327
|
}
|
|
174
328
|
if (event.validation.warnings.length > 0) {
|
|
175
329
|
lines.push("Warnings:");
|
|
@@ -179,7 +333,7 @@ const summarizeValidation = (event) => {
|
|
|
179
333
|
};
|
|
180
334
|
const surveyChangeTool = createTool({
|
|
181
335
|
id: TOOL_ID$9,
|
|
182
|
-
description: "Validate and queue one final, bounded, undoable survey change. This is not a dry run and does not mutate the live snapshot during the response.
|
|
336
|
+
description: "Validate and queue one final, bounded, undoable survey change. This is not a dry run and does not mutate the live snapshot during the response. The live snapshot is immutable: item-editing operations target existing items, while each create-item must contain that new item's complete initial config, content, options, fields, and embedded expressions. Multiple create-item operations may be ordered by dependency in one proposal. Omit continuationMode only on the first mutation call in a turn; every later mutation call must use \"append\" for independent additional work or \"replace\" for a correction. Every operation uses \"kind\".",
|
|
183
337
|
inputSchema: inputSchema$9,
|
|
184
338
|
outputSchema: surveyChangeSetSchema,
|
|
185
339
|
mcp: { annotations: {
|
|
@@ -238,7 +392,7 @@ const inputSchema$8 = z.object({
|
|
|
238
392
|
mutations: z.array(z.record(z.string(), z.unknown())).min(1).max(40).optional().describe("For prepare: expression mutation objects using kebab-case kind names. 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."),
|
|
239
393
|
continuationMode: continuationModeSchema,
|
|
240
394
|
inspectedContext: z.array(z.string().max(240)).max(20).optional()
|
|
241
|
-
}).superRefine((value, ctx) => {
|
|
395
|
+
}).strict().superRefine((value, ctx) => {
|
|
242
396
|
if (value.action !== "prepare") return;
|
|
243
397
|
if (!value.intent) ctx.addIssue({
|
|
244
398
|
code: z.ZodIssueCode.custom,
|
|
@@ -260,6 +414,7 @@ const contextOutputSchema = z.object({
|
|
|
260
414
|
ok: z.boolean(),
|
|
261
415
|
action: z.literal("context"),
|
|
262
416
|
modelSummary: z.string(),
|
|
417
|
+
listOrdering: z.record(z.string(), z.string()).describe("Meaning of each returned list. Expression references are not positional."),
|
|
263
418
|
responseSlots: z.array(z.object({
|
|
264
419
|
ref: z.string(),
|
|
265
420
|
valueType: z.string().optional()
|
|
@@ -296,14 +451,15 @@ const rejectedEvent = ({ issues, summary, turnId, warnings = [] }) => ({
|
|
|
296
451
|
const summarizeDraftEvent = (event) => {
|
|
297
452
|
const lines = [`${event.status === "validated" ? "Validated" : "Rejected"} expression change: ${event.summary}`, `Change id: ${event.id}`];
|
|
298
453
|
if (event.operations.length > 0) lines.push(`Operations: ${event.operations.map((operation) => operation.kind).join(", ")}`);
|
|
299
|
-
if (event.status === "rejected")
|
|
454
|
+
if (event.status === "rejected") {
|
|
455
|
+
lines.push("Apply status: blocked; this candidate is not authorized.");
|
|
456
|
+
if (event.recovery?.requiredContinuationMode) lines.push(`Required recovery: resubmit the complete intended proposal with continuationMode "${event.recovery.requiredContinuationMode}". No survey change from this turn can be authorized until that replacement validates.`);
|
|
457
|
+
else if (event.recovery) lines.push(`Required recovery: resubmit the complete proposal with an explicit continuationMode (${event.recovery.allowedContinuationModes.join(" or ")}).`);
|
|
458
|
+
}
|
|
300
459
|
if (event.supersedesChangeIds?.length) lines.push(event.status === "validated" ? `Queue: replaces ${event.supersedesChangeIds.length} earlier candidate proposal(s) from this response.` : `Queue: discarded ${event.supersedesChangeIds.length} earlier candidate proposal(s); their work is not retained or authorized.`);
|
|
301
460
|
if (event.validation.issues.length > 0) {
|
|
302
461
|
lines.push("Issues:");
|
|
303
462
|
for (const issue of event.validation.issues) lines.push(`- ${issue.code}: ${issue.message}`);
|
|
304
|
-
const issueCodes = new Set(event.validation.issues.map((issue) => issue.code));
|
|
305
|
-
if (issueCodes.has("change-mode-required")) lines.push("Recovery hint: retry the complete intended proposal with continuationMode \"append\" for independent additional work or \"replace\" for a correction. Nothing from the ambiguous sequence is currently authorized.");
|
|
306
|
-
if (issueCodes.has("change-mode-repair-required")) lines.push("Recovery hint: the turn remains blocked. Retry the complete intended proposal with continuationMode \"replace\". Only a validated replacement clears the block; after that, use \"append\" for later independent chunks.");
|
|
307
463
|
}
|
|
308
464
|
if (event.validation.warnings.length > 0) {
|
|
309
465
|
lines.push("Warnings:");
|
|
@@ -345,11 +501,17 @@ const buildContextOutput = (snapshot, input) => {
|
|
|
345
501
|
"Display, disabled, validation, and prefill.when expressions must return boolean.",
|
|
346
502
|
"Use response refs exactly as listed and check their value types before choosing functions.",
|
|
347
503
|
"For choice options: use eq(response reference, reference const) when the slot type is reference; use list_contains(response reference[], reference const) only when the slot type is reference[].",
|
|
504
|
+
"Response-slot order: set-like deterministic snapshot construction order; it has no survey or respondent-visible meaning.",
|
|
348
505
|
`Response slots (${responseSlots.length}): ${responseSlots.slice(0, 80).map((slot) => `${slot.ref}${slot.valueType ? `:${slot.valueType}` : ""}`).join(", ")}`,
|
|
349
506
|
responseSlots.length > 80 ? "Response slot list truncated in summary; inspect context result for more." : void 0,
|
|
350
507
|
"Functions: and, or, not, eq, gt, gte, lt, lte, in_range, list_contains, sum, min, max, str_eq, date_eq.",
|
|
351
508
|
expressionLocations ? `Existing expression locations: ${expressionLocations.filter((entry) => entry.locations.length > 0).map((entry) => `${entry.key}(${entry.itemId}) -> ${entry.locations.join("|")}`).join("; ") || "none"}` : void 0
|
|
352
509
|
].filter((line) => Boolean(line)).join("\n"),
|
|
510
|
+
listOrdering: {
|
|
511
|
+
responseSlots: "Set-like deterministic snapshot construction order; position has no survey or respondent-visible meaning.",
|
|
512
|
+
expressionLocations: "Stored surveyItems array order; locations within an item are grouped by expression surface, not ranked or respondent-visible order.",
|
|
513
|
+
"expressionLocations[].locations": "Grouped by expression surface (root, components, validations, prefills); position has no semantic meaning."
|
|
514
|
+
},
|
|
353
515
|
responseSlots,
|
|
354
516
|
...expressionLocations ? { expressionLocations } : {}
|
|
355
517
|
};
|
|
@@ -375,6 +537,7 @@ const surveyExpressionTool = createTool({
|
|
|
375
537
|
ok: false,
|
|
376
538
|
action: "context",
|
|
377
539
|
modelSummary: "No live editor snapshot is available for expression work.",
|
|
540
|
+
listOrdering: { responseSlots: "Set-like; unavailable because no live snapshot was provided." },
|
|
378
541
|
responseSlots: []
|
|
379
542
|
};
|
|
380
543
|
const { changeCollector, turnId } = requireSurveyAssistantTurnState(requestContext);
|
|
@@ -487,6 +650,7 @@ const outputSchema$6 = z.object({
|
|
|
487
650
|
revision: z.number().int().nonnegative().optional(),
|
|
488
651
|
contentHash: z.string().optional(),
|
|
489
652
|
scopes: z.array(contextScopeSchema).optional(),
|
|
653
|
+
listOrdering: z.record(z.string(), z.string()).optional().describe("Meaning of each returned list. A list is positional only when its entry says so."),
|
|
490
654
|
summary: z.object({
|
|
491
655
|
sessionId: z.string().nullable(),
|
|
492
656
|
view: z.string(),
|
|
@@ -528,6 +692,7 @@ const outputSchema$6 = z.object({
|
|
|
528
692
|
returned: z.number().int().nonnegative(),
|
|
529
693
|
nextCursor: z.string().optional(),
|
|
530
694
|
truncated: z.boolean(),
|
|
695
|
+
ordering: z.string(),
|
|
531
696
|
items: z.array(itemSummarySchema),
|
|
532
697
|
note: z.string().optional()
|
|
533
698
|
}).optional(),
|
|
@@ -538,6 +703,7 @@ const outputSchema$6 = z.object({
|
|
|
538
703
|
returned: z.number().int().nonnegative(),
|
|
539
704
|
nextCursor: z.string().optional(),
|
|
540
705
|
truncated: z.boolean(),
|
|
706
|
+
ordering: z.string(),
|
|
541
707
|
slots: z.array(z.string()),
|
|
542
708
|
note: z.string().optional()
|
|
543
709
|
}).optional(),
|
|
@@ -691,6 +857,7 @@ const buildOutline = (snapshot, input) => {
|
|
|
691
857
|
returned: page.items.length,
|
|
692
858
|
nextCursor: page.nextCursor,
|
|
693
859
|
truncated: page.truncated,
|
|
860
|
+
ordering: strategy === "focused-snapshot-outline" ? "Survey-tree preorder: configured group-child order is preserved; unparented items are appended by item id." : strategy === "direct-children" ? "Stored group-child order; this is not a stable respondent-visible order if that group shuffles children." : strategy === "query-match" ? "Survey-tree preorder after filtering by the query; this is not relevance-ranked." : "Relationship grouping for the focused item, not a single positional survey order.",
|
|
694
861
|
items: page.items,
|
|
695
862
|
note
|
|
696
863
|
};
|
|
@@ -707,6 +874,7 @@ const buildResponseSlots = (snapshot, input) => {
|
|
|
707
874
|
returned: page.items.length,
|
|
708
875
|
nextCursor: page.nextCursor,
|
|
709
876
|
truncated: page.truncated,
|
|
877
|
+
ordering: "Set-like response references in deterministic snapshot construction order; do not interpret their position as survey or respondent order.",
|
|
710
878
|
slots: page.items
|
|
711
879
|
};
|
|
712
880
|
};
|
|
@@ -716,9 +884,9 @@ const summarizeForModel$3 = (output) => {
|
|
|
716
884
|
if (output.summary) {
|
|
717
885
|
const selected = output.summary.selectedItemId ?? "none";
|
|
718
886
|
const surveyKey = output.summary.surveyKey ?? "not set";
|
|
719
|
-
lines.push(`Summary: view=${output.summary.view}; selectedItemId=${selected}; locale=${output.summary.selectedLocale}; surveyKey=${surveyKey}; itemCount=${output.summary.itemCount}.`);
|
|
887
|
+
lines.push(`Summary: view=${output.summary.view}; selectedItemId=${selected}; locale=${output.summary.selectedLocale}; surveyKey=${surveyKey}; itemCount=${output.summary.itemCount} (excluding the structural root group).`);
|
|
720
888
|
if (output.summary.rootItem) lines.push(`Root group for top-level create-item target.parentItemId: ${output.summary.rootItem.fullKey} (id=${output.summary.rootItem.itemId}, key=${output.summary.rootItem.key}).`);
|
|
721
|
-
lines.push(`Outline access: ${output.summary.outlineItemCount} item(s) are pageable.`);
|
|
889
|
+
lines.push(`Outline access: ${output.summary.outlineItemCount} item(s), including the structural root group, are pageable.`);
|
|
722
890
|
const creatableDetails = output.summary.itemTypeDetails.filter((entry) => entry.create === "deterministic").map((entry) => {
|
|
723
891
|
const primarySurface = entry.contentSurfaces.find((surface) => surface.role === "primary");
|
|
724
892
|
const fixedSurfaces = entry.contentSurfaces.filter((surface) => !surface.pattern).map((surface) => surface.key);
|
|
@@ -726,7 +894,8 @@ const summarizeForModel$3 = (output) => {
|
|
|
726
894
|
const contentKeys = [
|
|
727
895
|
primarySurface ? `primary=${primarySurface.key}` : void 0,
|
|
728
896
|
fixedSurfaces.length ? `visible=${fixedSurfaces.join("|")}` : void 0,
|
|
729
|
-
patterns.length ? `dynamic=${patterns.join("|")}` : void 0
|
|
897
|
+
patterns.length ? `dynamic=${patterns.join("|")}` : void 0,
|
|
898
|
+
entry.authoring?.compactHint
|
|
730
899
|
].filter((value) => Boolean(value)).join("; ");
|
|
731
900
|
return contentKeys ? `${entry.itemType} (${contentKeys})` : entry.itemType;
|
|
732
901
|
});
|
|
@@ -739,9 +908,13 @@ const summarizeForModel$3 = (output) => {
|
|
|
739
908
|
if (output.outline) {
|
|
740
909
|
lines.push(`Outline (${output.outline.strategy}${output.outline.mode ? `, mode=${output.outline.mode}` : ""}): ${output.outline.returned}/${output.outline.totalAvailable} rows returned.`);
|
|
741
910
|
for (const item of output.outline.items) lines.push(`- ${item.fullKey} (${item.itemType})${item.itemLabel ? ` - ${item.itemLabel}` : ""}`);
|
|
911
|
+
lines.push(`Outline order: ${output.outline.ordering}`);
|
|
742
912
|
if (output.outline.nextCursor) lines.push(`More outline rows are available with cursor ${output.outline.nextCursor}.`);
|
|
743
913
|
}
|
|
744
|
-
if (output.responseSlots)
|
|
914
|
+
if (output.responseSlots) {
|
|
915
|
+
lines.push(output.responseSlots.available ? `Response slots: ${output.responseSlots.slots.join(", ") || "none"}` : `Response slots unavailable: ${output.responseSlots.note ?? "not indexed"}.`);
|
|
916
|
+
if (output.responseSlots.available) lines.push(`Response-slot order: ${output.responseSlots.ordering}`);
|
|
917
|
+
}
|
|
745
918
|
if (output.uiContext) lines.push(`UI context: activeSurface=${output.uiContext.activeSurface ?? "not provided"}; openPanels=${output.uiContext.openPanels.join(", ") || "none"}; highlights=${output.uiContext.highlights.map((entry) => entry.label ?? entry.itemId ?? entry.componentId ?? entry.kind).join(", ") || "none"}.`);
|
|
746
919
|
if (output.history) lines.push(`Recent editor history (${output.history.currentIndex + 1}/${output.history.totalEntries}): ${output.history.recent.map((entry) => `${entry.index}:${entry.label}${entry.isCurrent ? " [current]" : ""}`).join("; ") || "none"}.`);
|
|
747
920
|
return lines.join("\n");
|
|
@@ -772,11 +945,32 @@ const surveyGetCurrentContextTool = createTool({
|
|
|
772
945
|
scopes: input.scopes
|
|
773
946
|
};
|
|
774
947
|
const scopes = unique(input.scopes);
|
|
948
|
+
const listOrdering = {};
|
|
949
|
+
if (scopes.includes("summary")) Object.assign(listOrdering, {
|
|
950
|
+
"summary.recentItemIds": "Most-recent-first UI history; not survey structure.",
|
|
951
|
+
"summary.locales": "Selected locale first, then remaining source locale order; locale position has no survey meaning.",
|
|
952
|
+
"summary.availableItemTypes": "Capability registry order; treat as a set of available types.",
|
|
953
|
+
"summary.deterministicCreateItemTypes": "Capability registry order; treat as a set of available types.",
|
|
954
|
+
"summary.itemTypeDetails": "Capability registry order; treat as a set of available type definitions."
|
|
955
|
+
});
|
|
956
|
+
if (scopes.includes("selected-item")) Object.assign(listOrdering, {
|
|
957
|
+
"selectedItem.pathItems": "Root-to-selected survey-tree path.",
|
|
958
|
+
"selectedItem.siblingItems": "Source survey item storage order; not necessarily respondent-visible order.",
|
|
959
|
+
"selectedItem.childItems": "Stored group-child order when the focused item is a group.",
|
|
960
|
+
"selectedItem.translationSnippets": "Grouped by locale and then source translation-key order; not positional survey content.",
|
|
961
|
+
"selectedItem.descendantItems": "Depth-first survey-tree traversal from the selected item."
|
|
962
|
+
});
|
|
963
|
+
if (scopes.includes("ui-context")) Object.assign(listOrdering, {
|
|
964
|
+
"uiContext.openPanels": "UI-provided set-like list; position has no meaning.",
|
|
965
|
+
"uiContext.highlights": "UI-provided set-like list; position has no meaning."
|
|
966
|
+
});
|
|
967
|
+
if (scopes.includes("history")) listOrdering["history.recent"] = "Chronological editor history, oldest to newest within this returned window.";
|
|
775
968
|
const output = {
|
|
776
969
|
ok: true,
|
|
777
970
|
revision: snapshot.version.revision,
|
|
778
971
|
contentHash: snapshot.version.contentHash,
|
|
779
|
-
scopes
|
|
972
|
+
scopes,
|
|
973
|
+
...Object.keys(listOrdering).length > 0 ? { listOrdering } : {}
|
|
780
974
|
};
|
|
781
975
|
if (scopes.includes("summary")) output.summary = buildSummary(snapshot);
|
|
782
976
|
if (scopes.includes("selected-item")) output.selectedItem = buildSelectedItem(snapshot, input);
|
|
@@ -814,6 +1008,7 @@ const outputSchema$5 = z.object({
|
|
|
814
1008
|
translations: z.array(translationEntrySchema).optional(),
|
|
815
1009
|
surveyChildren: z.array(itemSummarySchema).optional(),
|
|
816
1010
|
surveyChildrenTruncated: z.boolean().optional(),
|
|
1011
|
+
listOrdering: z.record(z.string(), z.string()).optional().describe("Meaning of each returned list. A list is positional only when its entry says so."),
|
|
817
1012
|
configDetails: itemConfigDetailsSchema.optional(),
|
|
818
1013
|
capabilityDetails: z.object({
|
|
819
1014
|
summary: z.string(),
|
|
@@ -824,21 +1019,21 @@ const summarizeConfigDetails = (configDetails) => {
|
|
|
824
1019
|
const lines = [`Config details (${configDetails.kind}): ${configDetails.summary.join("; ")}`];
|
|
825
1020
|
if (configDetails.mainResponseSlotId) lines.push(`Main response slot: ${configDetails.mainResponseSlotId}`);
|
|
826
1021
|
for (const option of configDetails.choiceOptions ?? []) {
|
|
827
|
-
lines.push(`- option ${option.key ?? option.id} (id=${option.id}, labelContentKey=${option.labelContentKey})`);
|
|
1022
|
+
lines.push(`- ${option.position}. option ${option.key ?? option.id} (id=${option.id}, labelContentKey=${option.labelContentKey})`);
|
|
828
1023
|
if (option.embeddedFormItemId || option.embeddedFormFieldGroupCount) {
|
|
829
1024
|
lines.push(` embedded form: itemId=${option.embeddedFormItemId ?? "inline"}, fieldGroups=${option.embeddedFormFieldGroupCount ?? 0}`);
|
|
830
1025
|
if (option.embeddedFormTranslationPrefix || option.embeddedFormResponseSlotPrefix) lines.push(` embedded form keys: translationPrefix=${option.embeddedFormTranslationPrefix ?? "n/a"}, responseSlotPrefix=${option.embeddedFormResponseSlotPrefix ?? "n/a"}`);
|
|
831
1026
|
}
|
|
832
1027
|
}
|
|
833
1028
|
for (const group of configDetails.formFieldGroups ?? []) {
|
|
834
|
-
lines.push(`- field group ${group.id}: ${group.fieldCount} field(s), titleContentKey=${group.titleContentKey}, layout=${group.layout.base}/${group.layout.xs}/${group.layout.sm}/${group.layout.md}/${group.layout.xl}`);
|
|
1029
|
+
lines.push(`- ${group.position}. field group ${group.id}: ${group.fieldCount} field(s), titleContentKey=${group.titleContentKey}, layout=${group.layout.base}/${group.layout.xs}/${group.layout.sm}/${group.layout.md}/${group.layout.xl}`);
|
|
835
1030
|
if (group.hasDisplayCondition !== void 0) lines.push(` hasDisplayCondition=${group.hasDisplayCondition ? "true" : "false"}`);
|
|
836
1031
|
for (const field of group.fields) {
|
|
837
|
-
lines.push(` - field ${field.key} (${field.type}, id=${field.id}, responseSlot=${field.responseSlotId}, labelContentKey=${field.labelContentKey})`);
|
|
1032
|
+
lines.push(` - ${field.position}. field ${field.key} (${field.type}, id=${field.id}, responseSlot=${field.responseSlotId}, labelContentKey=${field.labelContentKey})`);
|
|
838
1033
|
lines.push(` extra content keys: description=${field.descriptionContentKey}, error=${field.errorContentKey}${field.placeholderContentKey ? `, placeholder=${field.placeholderContentKey}` : ""}${field.unitContentKey ? `, unit=${field.unitContentKey}` : ""}${field.checkedLabelContentKey ? `, checkedLabel=${field.checkedLabelContentKey}` : ""}${field.uncheckedLabelContentKey ? `, uncheckedLabel=${field.uncheckedLabelContentKey}` : ""}`);
|
|
839
1034
|
if (field.validationTypes?.length) lines.push(` validations: ${field.validationTypes.join(", ")}`);
|
|
840
1035
|
if (field.validationMessageContentKeys?.length) lines.push(` validation message keys: ${field.validationMessageContentKeys.join(", ")}`);
|
|
841
|
-
if (field.selectOptions?.length) lines.push(` select options: ${field.selectOptions.map((option) => `${option.value ?? option.id} (${option.labelContentKey})`).join(", ")}`);
|
|
1036
|
+
if (field.selectOptions?.length) lines.push(` select options: ${field.selectOptions.map((option) => `${option.position}. ${option.value ?? option.id} (${option.labelContentKey})`).join(", ")}`);
|
|
842
1037
|
}
|
|
843
1038
|
}
|
|
844
1039
|
return lines;
|
|
@@ -854,7 +1049,10 @@ const summarizeForModel$2 = (output) => {
|
|
|
854
1049
|
for (const child of output.surveyChildren) lines.push(`- ${child.fullKey} (${child.itemType})${child.itemLabel ? ` - ${child.itemLabel}` : ""}`);
|
|
855
1050
|
if (output.surveyChildrenTruncated) lines.push("More children exist than were returned; narrow down or raise childrenLimit.");
|
|
856
1051
|
}
|
|
857
|
-
if (output.configDetails)
|
|
1052
|
+
if (output.configDetails) {
|
|
1053
|
+
if (output.configDetails.listOrdering) for (const [list, meaning] of Object.entries(output.configDetails.listOrdering)) lines.push(`List order (${list}): ${meaning}`);
|
|
1054
|
+
lines.push(...summarizeConfigDetails(output.configDetails));
|
|
1055
|
+
}
|
|
858
1056
|
if (output.capabilityDetails) {
|
|
859
1057
|
lines.push(`Item capability: ${output.capabilityDetails.summary}`);
|
|
860
1058
|
if (output.capabilityDetails.details !== void 0) lines.push(`Capability details: ${JSON.stringify(output.capabilityDetails.details)}`);
|
|
@@ -894,10 +1092,16 @@ const surveyGetItemDetailsTool = createTool({
|
|
|
894
1092
|
ok: false,
|
|
895
1093
|
reason: `No item matching "${input.itemId}" (by itemId, key, or fullKey) was found in the current context snapshot.`
|
|
896
1094
|
};
|
|
1095
|
+
const rawItem = rawItemsById.get(item.itemId);
|
|
1096
|
+
const rawConfig = rawItem?.config && typeof rawItem.config === "object" && !Array.isArray(rawItem.config) ? rawItem.config : void 0;
|
|
897
1097
|
const output = {
|
|
898
1098
|
ok: true,
|
|
899
1099
|
item,
|
|
900
|
-
translations: buildItemTranslationEntries(snapshot, item.itemId, input)
|
|
1100
|
+
translations: buildItemTranslationEntries(snapshot, item.itemId, input),
|
|
1101
|
+
listOrdering: {
|
|
1102
|
+
translations: "Grouped by locale and then source translation-key order; this list is not positional survey content.",
|
|
1103
|
+
surveyChildren: rawConfig?.shuffleItems === true ? "Stored group-child order; respondents see shuffled children, so this is not a stable respondent-visible order." : "Stored group-child order; this is the respondent-visible order when the parent is a group."
|
|
1104
|
+
}
|
|
901
1105
|
};
|
|
902
1106
|
if (input.includeSurveyChildren) {
|
|
903
1107
|
const allChildren = findDirectChildrenByFullKey(getKeyIndexEntries(snapshot), outlineById, item.fullKey);
|
|
@@ -906,15 +1110,14 @@ const surveyGetItemDetailsTool = createTool({
|
|
|
906
1110
|
output.surveyChildrenTruncated = allChildren.length > limit;
|
|
907
1111
|
}
|
|
908
1112
|
if (input.includeItemConfig) {
|
|
909
|
-
const rawItem = rawItemsById.get(item.itemId);
|
|
910
1113
|
output.configDetails = rawItem ? buildItemConfigDetails(rawItem) : void 0;
|
|
911
1114
|
output.capabilityDetails = rawItem ? inspectAssistantItem({
|
|
912
1115
|
capabilities: snapshot.trustedCapabilities,
|
|
913
1116
|
item: rawItem
|
|
914
1117
|
}) : void 0;
|
|
915
1118
|
if (rawItem?.itemType === "choiceItem" && output.configDetails?.choiceOptions) {
|
|
916
|
-
const
|
|
917
|
-
const rawOptions = Array.isArray(
|
|
1119
|
+
const rawChoiceConfig = rawItem.config && typeof rawItem.config === "object" && !Array.isArray(rawItem.config) ? rawItem.config : void 0;
|
|
1120
|
+
const rawOptions = Array.isArray(rawChoiceConfig?.options) ? rawChoiceConfig.options : [];
|
|
918
1121
|
for (const option of output.configDetails.choiceOptions) {
|
|
919
1122
|
const rawOption = rawOptions.find((candidate) => candidate && typeof candidate === "object" && "id" in candidate && candidate.id === option.id);
|
|
920
1123
|
const embeddedFormDetails = buildEmbeddedFormDetails(option, rawOption && typeof rawOption === "object" && "embeddedForm" in rawOption ? rawOption.embeddedForm : void 0);
|
|
@@ -950,6 +1153,7 @@ const outputSchema$4 = z.object({
|
|
|
950
1153
|
reason: z.string().optional(),
|
|
951
1154
|
revision: z.number().int().nonnegative().optional(),
|
|
952
1155
|
contentHash: z.string().optional(),
|
|
1156
|
+
listOrdering: z.record(z.string(), z.string()).optional().describe("Meaning of each returned list. Raw JSON arrays retain their stored order."),
|
|
953
1157
|
overview: z.object({
|
|
954
1158
|
topLevelKeys: z.array(z.string()),
|
|
955
1159
|
surveyItemCount: z.number().int().nonnegative(),
|
|
@@ -1101,6 +1305,7 @@ const summarizeForModel$1 = (output) => {
|
|
|
1101
1305
|
for (const item of output.overview.itemPaths.slice(0, 50)) lines.push(`- ${item.path}: ${item.key} (${item.itemType}, id=${item.id})${item.parentId ? ` parent=${item.parentId}` : ""}`);
|
|
1102
1306
|
if (output.overview.itemPaths.length > 50) lines.push("More item paths exist; request a specific path for exact raw JSON.");
|
|
1103
1307
|
}
|
|
1308
|
+
if (output.listOrdering) for (const [list, meaning] of Object.entries(output.listOrdering)) lines.push(`List order (${list}): ${meaning}`);
|
|
1104
1309
|
for (const item of output.items ?? []) {
|
|
1105
1310
|
if (!item.found) {
|
|
1106
1311
|
lines.push(`${item.identifier}: not found (${item.error ?? "unknown error"})`);
|
|
@@ -1149,6 +1354,13 @@ const surveyGetRawSurveyTool = createTool({
|
|
|
1149
1354
|
ok: true,
|
|
1150
1355
|
revision: snapshot.version.revision,
|
|
1151
1356
|
contentHash: snapshot.version.contentHash,
|
|
1357
|
+
listOrdering: {
|
|
1358
|
+
"overview.topLevelKeys": "Alphabetical key order; not survey content order.",
|
|
1359
|
+
"overview.locales": "Selected locale first, then remaining source locale order; locale position has no survey meaning.",
|
|
1360
|
+
"overview.itemPaths": "Stored surveyItems array order. The numeric segment in each JSON Pointer path is its zero-based stored position; this differs from group-child display order.",
|
|
1361
|
+
values: "Same order as the requested JSON Pointer paths.",
|
|
1362
|
+
items: "Same order as the requested itemIdentifiers."
|
|
1363
|
+
},
|
|
1152
1364
|
overview: input.paths || input.itemIdentifiers ? void 0 : buildOverview(snapshot),
|
|
1153
1365
|
items: input.itemIdentifiers ? buildItemValues(snapshot, {
|
|
1154
1366
|
itemIdentifiers: input.itemIdentifiers,
|
|
@@ -1200,6 +1412,7 @@ const outputSchema$3 = z.object({
|
|
|
1200
1412
|
returned: z.number().int().nonnegative().optional(),
|
|
1201
1413
|
nextCursor: z.string().optional(),
|
|
1202
1414
|
truncated: z.boolean().optional(),
|
|
1415
|
+
ordering: z.string().optional().describe("How results and their matches are ordered; this search output is not survey order."),
|
|
1203
1416
|
results: z.array(searchResultSchema).optional()
|
|
1204
1417
|
});
|
|
1205
1418
|
const STOP_WORDS = new Set([
|
|
@@ -1335,6 +1548,7 @@ const summarizeForModel = (output) => {
|
|
|
1335
1548
|
}
|
|
1336
1549
|
}
|
|
1337
1550
|
if (output.nextCursor) lines.push(`More search results are available with cursor ${output.nextCursor}.`);
|
|
1551
|
+
if (output.ordering) lines.push(`Search-result order: ${output.ordering}`);
|
|
1338
1552
|
lines.push("Use survey_inspect with action \"item-details\" and itemRef to inspect a result.");
|
|
1339
1553
|
return lines.join("\n");
|
|
1340
1554
|
};
|
|
@@ -1370,6 +1584,7 @@ const surveySearchItemsTool = createTool({
|
|
|
1370
1584
|
returned: page.items.length,
|
|
1371
1585
|
nextCursor: page.nextCursor,
|
|
1372
1586
|
truncated: page.truncated,
|
|
1587
|
+
ordering: "Results are ranked by descending text-match score, then item full key. Matches within each result are ranked by descending score. Neither order is survey or respondent-visible order.",
|
|
1373
1588
|
results: page.items
|
|
1374
1589
|
};
|
|
1375
1590
|
},
|
|
@@ -1504,6 +1719,10 @@ const listAssets = (input, snapshot) => {
|
|
|
1504
1719
|
totalAvailable: allAssets.length,
|
|
1505
1720
|
returned: assets.length,
|
|
1506
1721
|
...nextOffset < allAssets.length ? { nextCursor: String(nextOffset) } : {},
|
|
1722
|
+
listOrdering: {
|
|
1723
|
+
assets: "Alphabetical by assetId; position has no survey meaning.",
|
|
1724
|
+
"assets[].usages": "Deterministic survey translation traversal order; position has no semantic meaning."
|
|
1725
|
+
},
|
|
1507
1726
|
assets
|
|
1508
1727
|
};
|
|
1509
1728
|
};
|
|
@@ -1695,7 +1914,7 @@ const inputSchema = z.object({
|
|
|
1695
1914
|
alt: z.string().max(2e3).nullable().optional(),
|
|
1696
1915
|
continuationMode: z.enum(SURVEY_CHANGE_CONTINUATION_MODES).optional().describe("Required after any earlier mutation candidate in the turn. Use \"append\" to keep earlier candidates, including an imported asset; use \"replace\" only when resubmitting the complete intended proposal."),
|
|
1697
1916
|
summary: z.string().min(1).max(500)
|
|
1698
|
-
});
|
|
1917
|
+
}).strict();
|
|
1699
1918
|
const slug = (value) => value.toLowerCase().replace(/\.[^.]+$/, "").replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 100) || "image";
|
|
1700
1919
|
const OMITTED_EMBEDDED_IMAGE_DATA = "[embedded image data omitted from transcript]";
|
|
1701
1920
|
const getAssetReferenceLabels = (snapshot, assetId) => {
|
|
@@ -1876,4 +2095,4 @@ const surveyAssistantTools = Object.freeze({
|
|
|
1876
2095
|
//#endregion
|
|
1877
2096
|
export { surveyAuditTool as i, surveyAssistantTools as n, surveyAssetTool as r, SURVEY_ASSISTANT_TOOL_IDS as t };
|
|
1878
2097
|
|
|
1879
|
-
//# sourceMappingURL=tools-
|
|
2098
|
+
//# sourceMappingURL=tools-DDXaJ8Za.mjs.map
|