@esheet/builder 0.0.4-0 → 0.0.4-2

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.
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Builder icon components — ported from questionnaire-builder (old QB).
4
+ *
5
+ * All icons accept a `className` prop and render inline SVGs using `currentColor`.
6
+ * Usage: <TrashIcon className="ms:w-5 ms:h-5 ms:text-mstextmuted" />
7
+ */
8
+ import React from 'react';
9
+ const eq = (a, b) => a.className === b.className;
10
+ // ---------------------------------------------------------------------------
11
+ // Shared icons — re-exported from @esheet/fields
12
+ // ---------------------------------------------------------------------------
13
+ export { TrashIcon, PlusIcon, ArrowUpIcon, ArrowDownIcon, UpDownArrowIcon, } from '@esheet/fields';
14
+ // ---------------------------------------------------------------------------
15
+ // Field Wrapper actions
16
+ // ---------------------------------------------------------------------------
17
+ export const ViewBigIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M12 10v-7l3 3" }), _jsx("path", { d: "M9 6l3 -3" }), _jsx("path", { d: "M12 14v7l3 -3" }), _jsx("path", { d: "M9 18l3 3" }), _jsx("path", { d: "M18 3h1a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-1" }), _jsx("path", { d: "M6 3h-1a2 2 0 0 0 -2 2v14a2 2 0 0 0 2 2h1" })] })), eq);
18
+ export const ViewSmallIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M12 3v7l3 -3" }), _jsx("path", { d: "M9 7l3 3" }), _jsx("path", { d: "M12 21v-7l3 3" }), _jsx("path", { d: "M9 17l3 -3" }), _jsx("path", { d: "M18 9h1a2 2 0 0 1 2 2v2a2 2 0 0 1 -2 2h-1" }), _jsx("path", { d: "M6 9h-1a2 2 0 0 0 -2 2v2a2 2 0 0 0 2 2h1" })] })), eq);
19
+ export const EditIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M7 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-1" }), _jsx("path", { d: "M20.385 6.585a2.1 2.1 0 0 0-2.97-2.97L9 12v3h3zM16 5l3 3" })] })), eq);
20
+ // ---------------------------------------------------------------------------
21
+ // ToolPanel category icons
22
+ // ---------------------------------------------------------------------------
23
+ export const TextFieldsIcon = React.memo(({ className = '' }) => (_jsx("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M4 8V6a2 2 0 0 1 2-2h2M4 16v2a2 2 0 0 0 2 2h2m8-16h2a2 2 0 0 1 2 2v2m-4 12h2a2 2 0 0 0 2-2v-2m-8 0V9M9 9h6" }) })), eq);
24
+ export const SelectionFieldsIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }), _jsx("path", { d: "m9 11l3 3l3-3" })] })), eq);
25
+ export const RatingIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M11 6h9" }), _jsx("path", { d: "M11 12h9" }), _jsx("path", { d: "M12 18h8" }), _jsx("path", { d: "M4 16a2 2 0 1 1 4 0c0 0.591 -0.5 1 -1 1.5L4 20h4" }), _jsx("path", { d: "M6 10V4L4 6" })] })), eq);
26
+ export const MatrixIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M4 5a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M11 5a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M18 5a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M4 12a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M11 12a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M18 12a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M4 19a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M11 19a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" }), _jsx("path", { d: "M18 19a1 1 0 1 0 2 0 1 1 0 1 0 -2 0" })] })), eq);
27
+ export const RichContentIcon = React.memo(({ className = '' }) => (_jsx("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "m15 7 -6.5 6.5a1.5 1.5 0 0 0 3 3L18 10a3 3 0 0 0 -6 -6l-6.5 6.5a4.5 4.5 0 0 0 9 9L21 13" }) })), eq);
28
+ export const OrganizationIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M9 4h3l2 2h5a2 2 0 0 1 2 2v7a2 2 0 0 1 -2 2H9a2 2 0 0 1 -2 -2V6a2 2 0 0 1 2 -2" }), _jsx("path", { d: "M17 17v2a2 2 0 0 1 -2 2H5a2 2 0 0 1 -2 -2v-9a2 2 0 0 1 2 -2h2" })] })), eq);
29
+ // ---------------------------------------------------------------------------
30
+ // BuilderHeader — mode toggle icons
31
+ // ---------------------------------------------------------------------------
32
+ export const VEditorIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", children: [_jsx("path", { d: "M4 20h4L18.5 9.5a2.828 2.828 0 1 0 -4 -4L4 16v4" }), _jsx("path", { d: "m13.5 6.5 4 4" }), _jsx("path", { d: "m19 16 -2 3h4l-2 3" })] })), eq);
33
+ export const PreviewIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", children: [_jsx("path", { d: "M15 8h0.01" }), _jsx("path", { d: "M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3H6a3 3 0 0 1 -3 -3V6z" }), _jsx("path", { d: "m3 16 5 -5c0.928 -0.893 2.072 -0.893 3 0l5 5" }), _jsx("path", { d: "m14 14 1 -1c0.928 -0.893 2.072 -0.893 3 0l3 3" })] })), eq);
34
+ // ---------------------------------------------------------------------------
35
+ // BuilderHeader — action icons
36
+ // ---------------------------------------------------------------------------
37
+ export const UploadIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2" }), _jsx("path", { d: "M7 9l5 -5l5 5" }), _jsx("path", { d: "M12 4l0 12" })] })), eq);
38
+ export const DownloadIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2" }), _jsx("path", { d: "M7 11l5 5l5 -5" }), _jsx("path", { d: "M12 4l0 12" })] })), eq);
39
+ export const CodeIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "m7 8 -4 4 4 4" }), _jsx("path", { d: "m17 8 4 4 -4 4" }), _jsx("path", { d: "m14 4 -4 16" })] })), eq);
40
+ // ---------------------------------------------------------------------------
41
+ // Misc / shared
42
+ // ---------------------------------------------------------------------------
43
+ export const ChevronIcon = React.memo(({ className = '' }) => (_jsx("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M6 9l6 6l6 -6" }) })), eq);
44
+ export const XIcon = React.memo(({ className = '' }) => (_jsx("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12" }) })), eq);
45
+ export const CheckIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M5 12l5 5l10 -10" })] })), eq);
46
+ export const DragHandleIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "currentColor", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("circle", { cx: "9", cy: "5", r: "1" }), _jsx("circle", { cx: "9", cy: "12", r: "1" }), _jsx("circle", { cx: "9", cy: "19", r: "1" }), _jsx("circle", { cx: "15", cy: "5", r: "1" }), _jsx("circle", { cx: "15", cy: "12", r: "1" }), _jsx("circle", { cx: "15", cy: "19", r: "1" })] })), eq);
47
+ export const LogicIcon = React.memo(({ className = '' }) => (_jsxs("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }), _jsx("path", { d: "M22 12h-5" }), _jsx("path", { d: "M2 9h5" }), _jsx("path", { d: "M2 15h5" }), _jsx("path", { d: "M9 5c6 0 8 3.5 8 7s-2 7 -8 7h-2v-14h2" })] })), eq);
@@ -0,0 +1,4 @@
1
+ export { executeToolCall } from './tool-executor.js';
2
+ export { BUILDER_TOOL_DEFINITIONS } from './tool-definitions.js';
3
+ export { BUILDER_SYSTEM_PROMPT } from './system-prompt.js';
4
+ export { useBuilderMcpToolHandler } from './useBuilderToolBridge.js';
@@ -0,0 +1,9 @@
1
+ export const BUILDER_SYSTEM_PROMPT = 'Form builder assistant. Field types: text, longtext, multitext, radio, check, boolean, dropdown, multiselectdropdown, rating, ranking, slider, singlematrix, multimatrix, image, html, signature, diagram, display, section. ' +
2
+ 'STRICT WORKFLOW: Before editing options/rows/columns on any field, call get_form_summary first to confirm the fieldType. ' +
3
+ 'singlematrix and multimatrix fields are created empty (no default rows or columns) — after creating one, use add_row/add_column to populate it. Use update_row/remove_row for rows and update_column/remove_column for columns — NEVER use add_option on matrix fields. ' +
4
+ 'add_option is ONLY for: radio, check, boolean, dropdown, multiselectdropdown, rating, ranking, slider, multitext. ' +
5
+ 'IMPORTANT: When building a new form or questionnaire from scratch, ALWAYS call reset_form first to clear placeholder fields before adding new ones. ' +
6
+ 'When using sections: first create the section field, then pass its ID as parentId on each subsequent create_field call to place fields inside it. ' +
7
+ 'PREVIEW FILL WORKFLOW: When asked to fill the preview form, call fill_field for each field. Each response includes filledCount and unfilledFields (only fields still needing values). You are done when unfilledFields is empty. Never skip a field; generate realistic mock values for all fields including dates and times. ' +
8
+ 'TEXT FIELD FORMATS: each field includes a valueFormat property — use it exactly (YYYY-MM-DD for date, YYYY-MM-DDTHH:mm for datetime-local, YYYY-MM for month, HH:mm for time). Wrong formats are rejected. ' +
9
+ 'For conversational questions reply in plain text without calling a tool.';
@@ -0,0 +1,436 @@
1
+ export const BUILDER_TOOL_DEFINITIONS = [
2
+ {
3
+ type: 'function',
4
+ function: {
5
+ name: 'get_form_summary',
6
+ description: 'CALL THIS FIRST. Returns {formId, fieldCount, fields} where each field has: id, fieldType, question, required, optionCount, rowCount, columnCount, editWith, hasRules, hasValue. Use get_field for full option/row/column values when needed.',
7
+ parameters: { type: 'object', properties: {} },
8
+ },
9
+ },
10
+ {
11
+ type: 'function',
12
+ function: {
13
+ name: 'fill_field',
14
+ description: 'Set a preview response for ONE field. Returns { result, filledCount, unfilledFields } where unfilledFields contains ONLY the fields still needing values (with full details). You are done when unfilledFields is empty.\n\nField type rules:\n- radio/dropdown/boolean/rating/slider: single string matching an option value\n- check/multiselectdropdown: array of strings matching option values\n- ranking: ordered array of option value strings\n- multitext: array of strings, one per option slot\n- singlematrix: { "Row Label": "Column Label" } — call once per row, calls accumulate\n- multimatrix: { "Row Label": ["Col1", "Col2"] }\n- text: use the valueFormat from the field schema (YYYY-MM-DD for date, YYYY-MM-DDTHH:mm for datetime-local, YYYY-MM for month, HH:mm for time). Wrong formats are rejected with an error.',
15
+ parameters: {
16
+ type: 'object',
17
+ properties: {
18
+ fieldQuestion: { type: 'string' },
19
+ fieldId: { type: 'string' },
20
+ value: {},
21
+ },
22
+ required: ['value'],
23
+ },
24
+ },
25
+ },
26
+ {
27
+ type: 'function',
28
+ function: {
29
+ name: 'clear_responses',
30
+ description: 'Clear all responses.',
31
+ parameters: { type: 'object', properties: {} },
32
+ },
33
+ },
34
+ {
35
+ type: 'function',
36
+ function: {
37
+ name: 'get_responses',
38
+ description: 'Get current response values.',
39
+ parameters: { type: 'object', properties: {} },
40
+ },
41
+ },
42
+ {
43
+ type: 'function',
44
+ function: {
45
+ name: 'reset_form',
46
+ description: 'Clear all fields.',
47
+ parameters: { type: 'object', properties: {} },
48
+ },
49
+ },
50
+ {
51
+ type: 'function',
52
+ function: {
53
+ name: 'create_field',
54
+ description: 'Add one field. fieldType: text|longtext|radio|check|boolean|dropdown|multiselectdropdown|rating|ranking|slider|section|html|display|image|signature|diagram. properties: {inputType,unit,min,max,step}. Pass parentId to place the field directly inside a section. For "html" fields: set properties.htmlContent to a raw HTML string (e.g. "<p>Your message</p>") — do NOT use "question". For "display" fields: set properties.content to a markdown/formula string that may embed field values using {fieldId} syntax (e.g. "Your score is **{score-field}**") — do NOT use "question". For "section" fields: use properties.title instead of question.',
55
+ parameters: {
56
+ type: 'object',
57
+ properties: {
58
+ fieldType: { type: 'string' },
59
+ question: { type: 'string' },
60
+ required: { type: 'boolean' },
61
+ options: {
62
+ type: 'array',
63
+ items: {
64
+ type: 'object',
65
+ properties: { value: { type: 'string' } },
66
+ required: ['value'],
67
+ },
68
+ },
69
+ afterFieldId: { type: 'string' },
70
+ parentId: {
71
+ type: 'string',
72
+ description: 'ID of a section field to place this field inside.',
73
+ },
74
+ properties: { type: 'object', additionalProperties: true },
75
+ },
76
+ required: ['fieldType', 'question'],
77
+ },
78
+ },
79
+ },
80
+ {
81
+ type: 'function',
82
+ function: {
83
+ name: 'update_field',
84
+ description: 'Change scalar field properties (question, required, inputType, min, max, step, placeholder). Do NOT pass rows or columns here — use add_row/add_column instead. Identify by fieldQuestion or fieldId.',
85
+ parameters: {
86
+ type: 'object',
87
+ properties: {
88
+ fieldQuestion: { type: 'string' },
89
+ fieldId: { type: 'string' },
90
+ updates: { type: 'object', additionalProperties: true },
91
+ },
92
+ required: ['updates'],
93
+ },
94
+ },
95
+ },
96
+ {
97
+ type: 'function',
98
+ function: {
99
+ name: 'delete_field',
100
+ description: 'Delete a field by fieldQuestion or fieldId.',
101
+ parameters: {
102
+ type: 'object',
103
+ properties: {
104
+ fieldQuestion: { type: 'string' },
105
+ fieldId: { type: 'string' },
106
+ },
107
+ },
108
+ },
109
+ },
110
+ {
111
+ type: 'function',
112
+ function: {
113
+ name: 'add_option',
114
+ description: 'Add an option to a radio, check, boolean, dropdown, multiselectdropdown, rating, ranking, slider, or multitext field. NOT for singlematrix/multimatrix — those use add_column or add_row. If you are unsure of the field type, call get_form_summary first.',
115
+ parameters: {
116
+ type: 'object',
117
+ properties: {
118
+ fieldQuestion: { type: 'string' },
119
+ fieldId: { type: 'string' },
120
+ value: { type: 'string' },
121
+ },
122
+ },
123
+ },
124
+ },
125
+ {
126
+ type: 'function',
127
+ function: {
128
+ name: 'update_option',
129
+ description: 'Update the label of an existing option on radio, check, dropdown, etc. NOT for singlematrix/multimatrix — use update_column or update_row instead. If you are unsure of the field type, call get_form_summary first. Use optionId from get_field, or currentValue to match by current label.',
130
+ parameters: {
131
+ type: 'object',
132
+ properties: {
133
+ fieldQuestion: { type: 'string' },
134
+ fieldId: { type: 'string' },
135
+ optionId: { type: 'string' },
136
+ currentValue: {
137
+ type: 'string',
138
+ description: 'Current label to match if optionId unknown',
139
+ },
140
+ value: { type: 'string' },
141
+ },
142
+ required: ['value'],
143
+ },
144
+ },
145
+ },
146
+ {
147
+ type: 'function',
148
+ function: {
149
+ name: 'remove_option',
150
+ description: 'Remove an option from a radio, check, dropdown, etc. by its ID or current label. NOT for singlematrix/multimatrix — use remove_column or remove_row instead. If you are unsure of the field type, call get_form_summary first.',
151
+ parameters: {
152
+ type: 'object',
153
+ properties: {
154
+ fieldQuestion: { type: 'string' },
155
+ fieldId: { type: 'string' },
156
+ optionId: { type: 'string' },
157
+ currentValue: {
158
+ type: 'string',
159
+ description: 'Current label to match if optionId unknown',
160
+ },
161
+ },
162
+ },
163
+ },
164
+ },
165
+ {
166
+ type: 'function',
167
+ function: {
168
+ name: 'get_field',
169
+ description: 'Get full details of one field including its options/rows/columns with their IDs.',
170
+ parameters: {
171
+ type: 'object',
172
+ properties: {
173
+ fieldQuestion: { type: 'string' },
174
+ fieldId: { type: 'string' },
175
+ },
176
+ },
177
+ },
178
+ },
179
+ {
180
+ type: 'function',
181
+ function: {
182
+ name: 'move_field',
183
+ description: 'Reorder a field to a new index position (0-based). Use get_form_summary to see current order.',
184
+ parameters: {
185
+ type: 'object',
186
+ properties: {
187
+ fieldQuestion: { type: 'string' },
188
+ fieldId: { type: 'string' },
189
+ toIndex: { type: 'number', description: '0-based target position' },
190
+ toParentId: {
191
+ type: 'string',
192
+ description: 'Parent section ID, or omit for root',
193
+ },
194
+ },
195
+ required: ['toIndex'],
196
+ },
197
+ },
198
+ },
199
+ {
200
+ type: 'function',
201
+ function: {
202
+ name: 'add_row',
203
+ description: 'Add a row to a matrix field (singlematrix/multimatrix).',
204
+ parameters: {
205
+ type: 'object',
206
+ properties: {
207
+ fieldQuestion: { type: 'string' },
208
+ fieldId: { type: 'string' },
209
+ value: { type: 'string' },
210
+ },
211
+ },
212
+ },
213
+ },
214
+ {
215
+ type: 'function',
216
+ function: {
217
+ name: 'update_row',
218
+ description: 'Update a matrix row label. Use rowId from get_field, or currentValue to match by current label.',
219
+ parameters: {
220
+ type: 'object',
221
+ properties: {
222
+ fieldQuestion: { type: 'string' },
223
+ fieldId: { type: 'string' },
224
+ rowId: { type: 'string' },
225
+ currentValue: {
226
+ type: 'string',
227
+ description: 'Current label to match if rowId unknown',
228
+ },
229
+ value: { type: 'string' },
230
+ },
231
+ required: ['value'],
232
+ },
233
+ },
234
+ },
235
+ {
236
+ type: 'function',
237
+ function: {
238
+ name: 'remove_row',
239
+ description: 'Remove a matrix row by its ID.',
240
+ parameters: {
241
+ type: 'object',
242
+ properties: {
243
+ fieldQuestion: { type: 'string' },
244
+ fieldId: { type: 'string' },
245
+ rowId: { type: 'string' },
246
+ },
247
+ required: ['rowId'],
248
+ },
249
+ },
250
+ },
251
+ {
252
+ type: 'function',
253
+ function: {
254
+ name: 'add_column',
255
+ description: 'Add a column to a matrix field.',
256
+ parameters: {
257
+ type: 'object',
258
+ properties: {
259
+ fieldQuestion: { type: 'string' },
260
+ fieldId: { type: 'string' },
261
+ value: { type: 'string' },
262
+ },
263
+ },
264
+ },
265
+ },
266
+ {
267
+ type: 'function',
268
+ function: {
269
+ name: 'update_column',
270
+ description: 'Update a matrix column label. Use columnId from get_field, or currentValue to match by current label.',
271
+ parameters: {
272
+ type: 'object',
273
+ properties: {
274
+ fieldQuestion: { type: 'string' },
275
+ fieldId: { type: 'string' },
276
+ columnId: { type: 'string' },
277
+ currentValue: {
278
+ type: 'string',
279
+ description: 'Current label to match if columnId unknown',
280
+ },
281
+ value: { type: 'string' },
282
+ },
283
+ required: ['value'],
284
+ },
285
+ },
286
+ },
287
+ {
288
+ type: 'function',
289
+ function: {
290
+ name: 'remove_column',
291
+ description: 'Remove a matrix column by its ID.',
292
+ parameters: {
293
+ type: 'object',
294
+ properties: {
295
+ fieldQuestion: { type: 'string' },
296
+ fieldId: { type: 'string' },
297
+ columnId: { type: 'string' },
298
+ },
299
+ required: ['columnId'],
300
+ },
301
+ },
302
+ },
303
+ {
304
+ type: 'function',
305
+ function: {
306
+ name: 'get_field_types',
307
+ description: 'List all available field types with their key, label, category, and whether they support options or matrix rows/columns. Call this before create_field if unsure which fieldType to use.',
308
+ parameters: { type: 'object', properties: {} },
309
+ },
310
+ },
311
+ {
312
+ type: 'function',
313
+ function: {
314
+ name: 'get_field_spec',
315
+ description: 'Get the full spec for a specific field type: capabilities, default properties, and placeholder hints.',
316
+ parameters: {
317
+ type: 'object',
318
+ properties: {
319
+ fieldType: {
320
+ type: 'string',
321
+ description: 'The field type key, e.g. "radio", "slider", "singlematrix"',
322
+ },
323
+ },
324
+ required: ['fieldType'],
325
+ },
326
+ },
327
+ },
328
+ {
329
+ type: 'function',
330
+ function: {
331
+ name: 'get_definition',
332
+ description: 'Export the complete current form as a JSON definition tree — all fields, options, rows, columns, and logic rules. Use this to inspect the full form structure or to verify logic rules on any field.',
333
+ parameters: { type: 'object', properties: {} },
334
+ },
335
+ },
336
+ {
337
+ type: 'function',
338
+ function: {
339
+ name: 'set_form_id',
340
+ description: 'Update the top-level form ID without replacing or modifying any fields.',
341
+ parameters: {
342
+ type: 'object',
343
+ properties: {
344
+ id: { type: 'string', description: 'The new form ID.' },
345
+ },
346
+ required: ['id'],
347
+ },
348
+ },
349
+ },
350
+ {
351
+ type: 'function',
352
+ function: {
353
+ name: 'add_field_rule',
354
+ description: 'Add a conditional logic rule to a field based on another field\'s response. Controls whether this field is visible, enabled, or required. effect: "visible"|"enable"|"required". logic: "AND"|"OR". Each condition: { targetId, operator, expected }. For option-based fields (radio, check, dropdown, etc.), expected must be the option ID (e.g. "o1") — use get_field to look up IDs. Operators: equals|notEquals|contains|includes|empty|notEmpty|greaterThan|greaterThanOrEqual|lessThan|lessThanOrEqual. Use "includes" for multi-select fields (check, multiselectdropdown, ranking). Use "empty"/"notEmpty" with no expected value.',
355
+ parameters: {
356
+ type: 'object',
357
+ properties: {
358
+ fieldQuestion: { type: 'string' },
359
+ fieldId: { type: 'string' },
360
+ effect: {
361
+ type: 'string',
362
+ enum: ['visible', 'enable', 'required'],
363
+ },
364
+ logic: {
365
+ type: 'string',
366
+ enum: ['AND', 'OR'],
367
+ },
368
+ conditions: {
369
+ type: 'array',
370
+ items: {
371
+ type: 'object',
372
+ properties: {
373
+ targetId: {
374
+ type: 'string',
375
+ description: 'Field ID whose response is checked.',
376
+ },
377
+ operator: {
378
+ type: 'string',
379
+ description: 'equals|notEquals|contains|includes|empty|notEmpty|greaterThan|greaterThanOrEqual|lessThan|lessThanOrEqual',
380
+ },
381
+ expected: {
382
+ type: 'string',
383
+ description: 'For option-based fields use the option ID (e.g. "o1"), not the label. Omit for empty/notEmpty.',
384
+ },
385
+ },
386
+ required: ['targetId', 'operator'],
387
+ },
388
+ },
389
+ },
390
+ required: ['effect', 'logic', 'conditions'],
391
+ },
392
+ },
393
+ },
394
+ {
395
+ type: 'function',
396
+ function: {
397
+ name: 'add_expression_rule',
398
+ description: 'Add a conditional logic rule to a field using a custom expression. Use this for complex conditions that field-based rules cannot express (e.g. arithmetic, multi-field combinations). The expression is evaluated in a safe sandbox — NOT full JavaScript. CRITICAL SYNTAX: field IDs MUST be wrapped in curly braces: {fieldId}. Example: `{text-3} > 4 && {rating-1} < 3`. Available operators: +,-,*,/,%, comparisons (==,!=,===,!==,>,>=,<,<=), logical (&&,||,!), property access (.length, .count on field refs). NOT available: ANY function calls (parseInt, parseFloat, Object.values, .includes, .find, .filter, etc.), bare field names without {}, loops, or assignments. NEVER use parseInt() — text fields with inputType "number" and rating/slider fields already resolve to numbers automatically, use them directly. Field values in expressions: text/longtext with inputType "number" → number. text/longtext otherwise → string. radio/dropdown/boolean/slider/rating → option label string (NOT id). check/multiselectdropdown/ranking → array of option label strings (use .count for length). singlematrix/multimatrix → object keyed by rowId (use .count for answered row count). Valid examples: `{f1} > 4 && {f2} < 3`, `{f3}.length > 0`, `{f4} == "Yes"`. Invalid: `parseInt({f1}) > 4`, `f1 > 4` (missing braces).',
399
+ parameters: {
400
+ type: 'object',
401
+ properties: {
402
+ fieldQuestion: { type: 'string' },
403
+ fieldId: { type: 'string' },
404
+ effect: {
405
+ type: 'string',
406
+ enum: ['visible', 'enable', 'required'],
407
+ },
408
+ expression: {
409
+ type: 'string',
410
+ description: 'Expression string. Use field IDs as variable names. No method calls allowed.',
411
+ },
412
+ },
413
+ required: ['effect', 'expression'],
414
+ },
415
+ },
416
+ },
417
+ {
418
+ type: 'function',
419
+ function: {
420
+ name: 'remove_rule',
421
+ description: 'Remove a conditional logic rule from a field by its 0-based index. Use get_field or get_definition to see existing rules and their indices.',
422
+ parameters: {
423
+ type: 'object',
424
+ properties: {
425
+ fieldQuestion: { type: 'string' },
426
+ fieldId: { type: 'string' },
427
+ ruleIndex: {
428
+ type: 'number',
429
+ description: '0-based index of the rule to remove.',
430
+ },
431
+ },
432
+ required: ['ruleIndex'],
433
+ },
434
+ },
435
+ },
436
+ ];