@esheet/renderer 0.0.4-1 → 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.
Files changed (33) hide show
  1. package/dist/index.d.ts +2 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +5240 -4197
  4. package/dist/lib/EsheetRenderer.d.ts +17 -4
  5. package/dist/lib/EsheetRenderer.d.ts.map +1 -1
  6. package/dist/lib/components/FieldNode.d.ts +2 -2
  7. package/dist/lib/components/FieldNode.d.ts.map +1 -1
  8. package/dist/lib/components/RendererBody.d.ts +1 -1
  9. package/dist/lib/hooks/useRendererInit.d.ts +2 -2
  10. package/dist/lib/hooks/useRendererInit.d.ts.map +1 -1
  11. package/dist/lib/mcp/tool-definitions.d.ts.map +1 -1
  12. package/dist/lib/mcp/tool-executor.d.ts +1 -1
  13. package/dist/lib/mcp/tool-executor.d.ts.map +1 -1
  14. package/dist/lib/mcp/useRendererToolBridge.d.ts +1 -1
  15. package/dist/lib/register-defaults.d.ts.map +1 -1
  16. package/dist/lib/renderer-tools.d.ts +2 -2
  17. package/dist/lib/renderer.d.ts +22 -1
  18. package/dist/lib/renderer.d.ts.map +1 -1
  19. package/package.json +5 -5
  20. package/dist/lib/EsheetRenderer.js +0 -115
  21. package/dist/lib/components/FieldNode.js +0 -96
  22. package/dist/lib/components/RendererBody.js +0 -45
  23. package/dist/lib/components/index.js +0 -2
  24. package/dist/lib/hooks/index.js +0 -1
  25. package/dist/lib/hooks/useRendererInit.js +0 -87
  26. package/dist/lib/mcp/index.js +0 -4
  27. package/dist/lib/mcp/system-prompt.js +0 -24
  28. package/dist/lib/mcp/tool-definitions.js +0 -66
  29. package/dist/lib/mcp/tool-executor.js +0 -55
  30. package/dist/lib/mcp/useRendererToolBridge.js +0 -53
  31. package/dist/lib/register-defaults.js +0 -36
  32. package/dist/lib/renderer-tools.js +0 -305
  33. package/dist/lib/renderer.js +0 -33
@@ -1,7 +1,7 @@
1
- import React from 'react';
2
- import { type FormResponse, type FormStore, type UIStore, type ValidationError } from '@esheet/core';
3
- import { type FhirQuestionnaireResponse, type ResponseExportOptions } from '@esheet/adapters';
4
- import { type RendererTools } from './renderer-tools.js';
1
+ import { default as React } from 'react';
2
+ import { FormResponse, FormStore, UIStore, ValidationError } from '@esheet/core';
3
+ import { FhirQuestionnaireResponse, ResponseExportOptions } from '@esheet/adapters';
4
+ import { RendererTools } from './renderer-tools.js';
5
5
  export interface EsheetRendererProps {
6
6
  /** Form definition — accepts FormDefinition, SurveyJS schema, MCP elicitation envelope,
7
7
  * or any of the above as a JSON/YAML string. Auto-detected and converted internally.
@@ -11,6 +11,11 @@ export interface EsheetRendererProps {
11
11
  className?: string;
12
12
  /** Initial form responses (pre-fill data) */
13
13
  initialResponses?: FormResponse;
14
+ /** When true, allows `dangerouslyAllowJS: true` in the loaded schema to take effect —
15
+ * enabling field calculations and `conditionType: 'js'` conditions.
16
+ * When `false` (default), dangerous JS never executes regardless of schema content.
17
+ * Only set to `true` when you fully control and trust the form schemas being rendered. */
18
+ allowDangerousJS?: boolean;
14
19
  /** When true, disables auto-detection of MCP/SurveyJS formats.
15
20
  * Only accepts a valid eSheet FormDefinition (or JSON/YAML string thereof). */
16
21
  strict?: boolean;
@@ -21,6 +26,14 @@ export interface EsheetRendererProps {
21
26
  * facade for MCP / AI tool integrations.
22
27
  */
23
28
  onRendererToolsReady?: (tools: RendererTools) => void;
29
+ /**
30
+ * When provided, a submit button is rendered at the bottom of the form.
31
+ * Called with the form response after all hard errors pass.
32
+ * If soft-required fields are unanswered, a bypass popup is shown first.
33
+ */
34
+ onSubmit?: (response: FormResponse) => void;
35
+ /** Label for the submit button. Defaults to `'Submit'`. */
36
+ submitLabel?: string;
24
37
  /**
25
38
  * Enable touch-optimized mode with larger touch targets.
26
39
  * - `true`: Always enable touch mode
@@ -1 +1 @@
1
- {"version":3,"file":"EsheetRenderer.d.ts","sourceRoot":"","sources":["../../src/lib/EsheetRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAW9E,MAAM,WAAW,mBAAmB;IAClC;;+FAE2F;IAC3F,aAAa,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAChC;oFACgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAMD,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE/C,gCAAgC;AAChC,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,GAAG;QACvD,gGAAgG;QAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,uDAAuD;AACvD,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,QAAQ,IAC/D,CAAC,SAAS,MAAM,GAAG,yBAAyB,GAAG,YAAY,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,cAAc,EAAE,MAAM,YAAY,CAAC;IACnC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,WAAW,EAAE,CAAC,CAAC,SAAS,cAAc,GAAG,QAAQ,EAC/C,OAAO,CAAC,EAAE,kBAAkB,GAAG;QAAE,MAAM,CAAC,EAAE,CAAC,CAAA;KAAE,KAC1C,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC1B,8BAA8B;IAC9B,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,4BAA4B;IAC5B,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM;QACtB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;QAC9B,MAAM,EAAE,eAAe,EAAE,CAAC;KAC3B,CAAC;IACF,sDAAsD;IACtD,kBAAkB,EAAE,MAAM,OAAO,CAAC;IAClC,iHAAiH;IACjH,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,+FAA+F;IAC/F,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc,kGA2BzB,CAAC"}
1
+ {"version":3,"file":"EsheetRenderer.d.ts","sourceRoot":"","sources":["../../src/lib/EsheetRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAY9E,MAAM,WAAW,mBAAmB;IAClC;;+FAE2F;IAC3F,aAAa,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAChC;;;+FAG2F;IAC3F,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;oFACgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAMD,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE/C,gCAAgC;AAChC,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,GAAG;QACvD,gGAAgG;QAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,uDAAuD;AACvD,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,QAAQ,IAC/D,CAAC,SAAS,MAAM,GAAG,yBAAyB,GAAG,YAAY,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,cAAc,EAAE,MAAM,YAAY,CAAC;IACnC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,WAAW,EAAE,CAAC,CAAC,SAAS,cAAc,GAAG,QAAQ,EAC/C,OAAO,CAAC,EAAE,kBAAkB,GAAG;QAAE,MAAM,CAAC,EAAE,CAAC,CAAA;KAAE,KAC1C,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC1B,8BAA8B;IAC9B,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,4BAA4B;IAC5B,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM;QACtB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;QAC9B,MAAM,EAAE,eAAe,EAAE,CAAC;KAC3B,CAAC;IACF,sDAAsD;IACtD,kBAAkB,EAAE,MAAM,OAAO,CAAC;IAClC,iHAAiH;IACjH,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,+FAA+F;IAC/F,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc,kGA+BzB,CAAC"}
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import type { FormStore, UIStore } from '@esheet/core';
1
+ import { default as React } from 'react';
2
+ import { FormStore, UIStore } from '@esheet/core';
3
3
  export interface FieldNodeProps {
4
4
  id: string;
5
5
  form: FormStore;
@@ -1 +1 @@
1
- {"version":3,"file":"FieldNode.d.ts","sourceRoot":"","sources":["../../../src/lib/components/FieldNode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAuB,SAAS,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,4CAiKpB,CAAC"}
1
+ {"version":3,"file":"FieldNode.d.ts","sourceRoot":"","sources":["../../../src/lib/components/FieldNode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAuB,SAAS,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,4CAoLpB,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { FormStore, UIStore } from '@esheet/core';
1
+ import { FormStore, UIStore } from '@esheet/core';
2
2
  export interface RendererBodyProps {
3
3
  form: FormStore;
4
4
  ui: UIStore;
@@ -1,4 +1,4 @@
1
- import { type FormResponse, type FormStore, type UIStore } from '@esheet/core';
1
+ import { FormResponse, FormStore, UIStore } from '@esheet/core';
2
2
  /**
3
3
  * Initialize renderer with form definition.
4
4
  *
@@ -8,5 +8,5 @@ import { type FormResponse, type FormStore, type UIStore } from '@esheet/core';
8
8
  * - MCP elicitation/create envelope
9
9
  * - SurveyJS schema (has top-level `pages` or `elements` array)
10
10
  */
11
- export declare function useRendererInit(form: FormStore, ui: UIStore, formData: unknown, initialResponses?: FormResponse, onValidationError?: (errors: string[]) => void, strict?: boolean, onReady?: () => void): void;
11
+ export declare function useRendererInit(form: FormStore, ui: UIStore, formData: unknown, initialResponses?: FormResponse, onValidationError?: (errors: string[]) => void, strict?: boolean, onReady?: () => void, allowDangerousJS?: boolean): void;
12
12
  //# sourceMappingURL=useRendererInit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useRendererInit.d.ts","sourceRoot":"","sources":["../../../src/lib/hooks/useRendererInit.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,EACb,MAAM,cAAc,CAAC;AAYtB;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,OAAO,EACX,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,YAAY,EAC/B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,EAC9C,MAAM,UAAQ,EACd,OAAO,CAAC,EAAE,MAAM,IAAI,GACnB,IAAI,CAqFN"}
1
+ {"version":3,"file":"useRendererInit.d.ts","sourceRoot":"","sources":["../../../src/lib/hooks/useRendererInit.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,EACb,MAAM,cAAc,CAAC;AAYtB;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,OAAO,EACX,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,YAAY,EAC/B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,EAC9C,MAAM,UAAQ,EACd,OAAO,CAAC,EAAE,MAAM,IAAI,EACpB,gBAAgB,UAAQ,GACvB,IAAI,CAyFN"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-definitions.d.ts","sourceRoot":"","sources":["../../../src/lib/mcp/tool-definitions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH;AAED,eAAO,MAAM,yBAAyB,EAAE,SAAS,cAAc,EAsE9D,CAAC"}
1
+ {"version":3,"file":"tool-definitions.d.ts","sourceRoot":"","sources":["../../../src/lib/mcp/tool-definitions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH;AAED,eAAO,MAAM,yBAAyB,EAAE,SAAS,cAAc,EAmG9D,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { RendererTools } from '../renderer-tools.js';
1
+ import { RendererTools } from '../renderer-tools.js';
2
2
  type ToolArgs = Record<string, unknown>;
3
3
  export declare function executeToolCall(toolName: string, args: ToolArgs, tools: RendererTools): string | Record<string, unknown>;
4
4
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"tool-executor.d.ts","sourceRoot":"","sources":["../../../src/lib/mcp/tool-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAExC,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,aAAa,GACnB,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBlC"}
1
+ {"version":3,"file":"tool-executor.d.ts","sourceRoot":"","sources":["../../../src/lib/mcp/tool-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAExC,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,aAAa,GACnB,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsBlC"}
@@ -1,4 +1,4 @@
1
- import type { RendererTools } from '../renderer-tools.js';
1
+ import { RendererTools } from '../renderer-tools.js';
2
2
  export interface UseRendererMcpToolHandlerOptions {
3
3
  /**
4
4
  * The DOM element to listen on for tool-call events.
@@ -1 +1 @@
1
- {"version":3,"file":"register-defaults.d.ts","sourceRoot":"","sources":["../../src/lib/register-defaults.ts"],"names":[],"mappings":"AAgCA,wBAAgB,sCAAsC,IAAI,IAAI,CA4B7D"}
1
+ {"version":3,"file":"register-defaults.d.ts","sourceRoot":"","sources":["../../src/lib/register-defaults.ts"],"names":[],"mappings":"AAkCA,wBAAgB,sCAAsC,IAAI,IAAI,CA8B7D"}
@@ -1,5 +1,5 @@
1
- import { type FormStore, type ValidationError } from '@esheet/core';
2
- import type { RenderFieldNode } from './renderer.js';
1
+ import { FormStore, ValidationError } from '@esheet/core';
2
+ import { RenderFieldNode } from './renderer.js';
3
3
  /** Summary of a single field, suitable for AI context. */
4
4
  export interface RendererFieldSummary {
5
5
  id: string;
@@ -1,7 +1,13 @@
1
- import { type FieldDefinition, type FormDefinition, type FormResponse } from '@esheet/core';
1
+ import { FieldDefinition, FormDefinition, FormResponse } from '@esheet/core';
2
2
  export interface RenderTreeOptions {
3
3
  /** Include fields that resolve to invisible (default: false). */
4
4
  includeHidden?: boolean;
5
+ /**
6
+ * Opt-in to allow dangerous JS execution. When `false` (default), any
7
+ * `dangerouslyAllowJS: true` in the schema is ignored — JS conditions always
8
+ * return `false`. Only set to `true` when you trust the schema content.
9
+ */
10
+ allowDangerousJS?: boolean;
5
11
  }
6
12
  export interface RenderFieldNode {
7
13
  /** Field identifier. */
@@ -14,6 +20,8 @@ export interface RenderFieldNode {
14
20
  enabled: boolean;
15
21
  /** Computed required state. */
16
22
  required: boolean;
23
+ /** Computed value from setValue effects (if any). */
24
+ computedValue?: string | number | null;
17
25
  /** Renderable child nodes (sections only). */
18
26
  children: RenderFieldNode[];
19
27
  }
@@ -21,8 +29,21 @@ export interface RenderFieldNode {
21
29
  * Build a render tree from form definition + responses.
22
30
  *
23
31
  * Sections are represented as nodes with nested `children`.
32
+ * Computed values from setValue effects are included in computedValue field.
24
33
  */
25
34
  export declare function renderer(definition: FormDefinition, responses?: FormResponse, options?: RenderTreeOptions): RenderFieldNode[];
26
35
  /** Alias for readability in consumers that prefer explicit naming. */
27
36
  export declare const buildRenderTree: typeof renderer;
37
+ /**
38
+ * Apply computed values from a render tree to a responses object.
39
+ *
40
+ * Iterates through the render tree and merges any computed values
41
+ * (from setValue effects) into the responses map. Wraps string/number
42
+ * values as FieldResponse answer objects.
43
+ *
44
+ * @param tree - Render tree with computed values.
45
+ * @param responses - Base responses object to merge into (is modified in-place).
46
+ * @returns Updated responses object.
47
+ */
48
+ export declare function applyComputedValues(tree: RenderFieldNode[], responses?: FormResponse): FormResponse;
28
49
  //# sourceMappingURL=renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/lib/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC5C,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,cAAc,EAC1B,SAAS,GAAE,YAAiB,EAC5B,OAAO,GAAE,iBAAsB,GAC9B,eAAe,EAAE,CA2CnB;AAED,sEAAsE;AACtE,eAAO,MAAM,eAAe,iBAAW,CAAC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/lib/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EAElB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC5C,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACvC,8CAA8C;IAC9C,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,cAAc,EAC1B,SAAS,GAAE,YAAiB,EAC5B,OAAO,GAAE,iBAAsB,GAC9B,eAAe,EAAE,CAyDnB;AAED,sEAAsE;AACtE,eAAO,MAAM,eAAe,iBAAW,CAAC;AAExC;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,eAAe,EAAE,EACvB,SAAS,GAAE,YAAiB,GAC3B,YAAY,CAgBd"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esheet/renderer",
3
- "version": "0.0.4-1",
3
+ "version": "0.0.4-2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/mieweb/eSheet"
@@ -38,9 +38,9 @@
38
38
  ]
39
39
  },
40
40
  "dependencies": {
41
- "@esheet/adapters": "0.0.4-1",
42
- "@esheet/core": "0.0.4-1",
43
- "@esheet/fields": "0.0.4-1",
41
+ "@esheet/adapters": "0.0.4-2",
42
+ "@esheet/core": "0.0.4-2",
43
+ "@esheet/fields": "0.0.4-2",
44
44
  "js-yaml": "^4.1.0"
45
45
  },
46
46
  "peerDependencies": {
@@ -55,4 +55,4 @@
55
55
  "@tailwindcss/cli": "^4.2.1",
56
56
  "tailwindcss": "^4.2.1"
57
57
  }
58
- }
58
+ }
@@ -1,115 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from 'react';
3
- import { createFormStore, createUIStore, normalizeResponses, hydrateDefinition, validateForm, } from '@esheet/core';
4
- import { exportResponseToFhir, } from '@esheet/adapters';
5
- import { createRendererTools } from './renderer-tools.js';
6
- import { FormStoreContext, UIContext, ZodIssuesPanel, useTouchMode, } from '@esheet/fields';
7
- import { ensureDefaultFieldComponentsRegistered } from './register-defaults.js';
8
- import { useRendererInit } from './hooks/useRendererInit.js';
9
- import { RendererBody } from './components/RendererBody.js';
10
- /**
11
- * EsheetRenderer - Read-only questionnaire form renderer
12
- *
13
- * Renders a form in fill-out mode with conditional visibility logic.
14
- * Reuses all field components from @esheet/fields.
15
- *
16
- * @example
17
- * ```tsx
18
- * const rendererRef = useRef<EsheetRendererHandle>(null);
19
- *
20
- * <EsheetRenderer
21
- * formData={myFormDefinition}
22
- * initialResponses={{ field1: 'answer' }}
23
- * ref={rendererRef}
24
- * />
25
- *
26
- * // Later: get responses
27
- * const responses = rendererRef.current?.getRawResponse();
28
- * ```
29
- */
30
- export const EsheetRenderer = React.forwardRef(function EsheetRenderer(props, ref) {
31
- ensureDefaultFieldComponentsRegistered();
32
- const formStore = React.useMemo(() => createFormStore(), []);
33
- const uiStore = React.useMemo(() => createUIStore(), []);
34
- React.useEffect(() => {
35
- if (props.onRendererToolsReady)
36
- props.onRendererToolsReady(createRendererTools(formStore));
37
- // eslint-disable-next-line react-hooks/exhaustive-deps
38
- }, [formStore]);
39
- return (_jsx(FormStoreContext.Provider, { value: formStore, children: _jsx(UIContext.Provider, { value: uiStore, children: _jsx(EsheetRendererInner, { ...props, formStore: formStore, uiStore: uiStore, ref: ref }) }) }));
40
- });
41
- const EsheetRendererInner = React.forwardRef(function EsheetRendererInner({ formDataInput: formData, className = '', initialResponses, strict = false, onReady, formStore, uiStore, touchMode, onTouchModeChange, }, ref) {
42
- const [validationErrors, setValidationErrors] = React.useState([]);
43
- // Touch mode state using shared hook
44
- const { isTouchEnabled, isManualOverride, setTouchMode: setTouchModeInternal, resetTouchMode: resetTouchModeInternal, } = useTouchMode({ mode: touchMode, onChange: onTouchModeChange });
45
- // Initialize form definition and set preview mode
46
- useRendererInit(formStore, uiStore, formData, initialResponses, setValidationErrors, strict, onReady);
47
- // Expose ref API
48
- React.useImperativeHandle(ref, () => ({
49
- getRawResponse: () => formStore.getState().responses,
50
- getResponse: (options) => {
51
- const state = formStore.getState();
52
- const responses = state.responses;
53
- if (options?.format === 'fhir') {
54
- // Build FHIR QuestionnaireResponse
55
- const normalizedAnswers = normalizeResponses(responses);
56
- // Try to get questionnaire URL from options or formSourceData
57
- const fhirMeta = state.formSourceData;
58
- const questionnaireUrl = options.fhir?.questionnaireUrl ??
59
- fhirMeta?.url ??
60
- `urn:uuid:${state.formId}`;
61
- const exportOptions = {
62
- questionnaireUrl,
63
- status: options.fhir?.status ?? 'completed',
64
- subject: options.fhir?.subject,
65
- author: options.fhir?.author,
66
- resourceId: options.fhir?.resourceId,
67
- };
68
- // Rebuild form definition from normalized state
69
- const formDefinition = {
70
- id: state.formId,
71
- fields: hydrateDefinition(state.normalized),
72
- _sourceData: state.formSourceData,
73
- };
74
- return exportResponseToFhir(formDefinition, normalizedAnswers, exportOptions);
75
- }
76
- // Native format (default)
77
- return responses;
78
- },
79
- getFormStore: () => formStore,
80
- getUIStore: () => uiStore,
81
- getValidResponse: () => {
82
- const state = formStore.getState();
83
- const errors = validateForm(state.normalized, state.responses);
84
- return {
85
- response: errors.length === 0 ? state.responses : null,
86
- errors,
87
- };
88
- },
89
- isTouchModeEnabled: () => isTouchEnabled,
90
- setTouchMode: setTouchModeInternal,
91
- resetTouchMode: resetTouchModeInternal,
92
- }), [
93
- formStore,
94
- uiStore,
95
- isTouchEnabled,
96
- setTouchModeInternal,
97
- resetTouchModeInternal,
98
- ]);
99
- // Determine if touch mode class should be applied
100
- // true: always apply, 'auto'/undefined: apply based on isTouchEnabled state, false: never apply (CSS only)
101
- const applyTouchClass = touchMode === true ||
102
- ((touchMode === 'auto' || touchMode === undefined) && isTouchEnabled);
103
- // Apply disabled class when user explicitly disabled touch mode (prevents CSS media query)
104
- const applyDisabledClass = isManualOverride && !isTouchEnabled;
105
- const rootClasses = [
106
- 'esheet-renderer-root',
107
- applyTouchClass && 'esheet-touch-active',
108
- applyDisabledClass && 'touch-mode-disabled',
109
- 'ms:w-full ms:max-w-2xl ms:mx-auto ms:p-4 ms:text-mstext',
110
- className,
111
- ]
112
- .filter(Boolean)
113
- .join(' ');
114
- return (_jsxs("div", { className: rootClasses, children: [_jsx(ZodIssuesPanel, { issues: validationErrors }), _jsx(RendererBody, { form: formStore, ui: uiStore })] }));
115
- });
@@ -1,96 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import React from 'react';
3
- import { getFieldComponent } from '@esheet/fields';
4
- /**
5
- * FieldNode - Renders a single field or section with recursive children
6
- *
7
- * Looks up the field component from the registry and passes field props.
8
- * For sections, recursively renders visible children.
9
- */
10
- export const FieldNode = React.memo(function FieldNode({ id, form, ui, depth = 1, }) {
11
- // Subscribe to field data
12
- const field = React.useSyncExternalStore((cb) => form.subscribe(cb), () => form.getState().getField(id), () => form.getState().getField(id));
13
- const normalized = React.useSyncExternalStore((cb) => form.subscribe(cb), () => form.getState().normalized, () => form.getState().normalized);
14
- const responses = React.useSyncExternalStore((cb) => form.subscribe(cb), () => form.getState().responses, () => form.getState().responses);
15
- // Get visible children for sections
16
- const visibleChildIds = React.useMemo(() => {
17
- if (!field || field.definition.fieldType !== 'section')
18
- return [];
19
- const node = normalized.byId[id];
20
- if (!node || node.childIds.length === 0)
21
- return [];
22
- const cache = new Map();
23
- const isFieldRenderable = (fieldId) => {
24
- const cached = cache.get(fieldId);
25
- if (cached !== undefined)
26
- return cached;
27
- const isVisible = form.getState().isVisible(fieldId);
28
- if (!isVisible) {
29
- cache.set(fieldId, false);
30
- return false;
31
- }
32
- const childNode = normalized.byId[fieldId];
33
- if (!childNode) {
34
- cache.set(fieldId, false);
35
- return false;
36
- }
37
- if (childNode.definition.fieldType !== 'section') {
38
- cache.set(fieldId, true);
39
- return true;
40
- }
41
- const hasRenderableChild = childNode.childIds.some((cid) => isFieldRenderable(cid));
42
- cache.set(fieldId, hasRenderableChild);
43
- return hasRenderableChild;
44
- };
45
- return node.childIds.filter((childId) => isFieldRenderable(childId));
46
- }, [field, id, form, normalized, responses]);
47
- // Render nested children for sections
48
- const nestedChildren = React.useMemo(() => {
49
- if (!field ||
50
- field.definition.fieldType !== 'section' ||
51
- visibleChildIds.length === 0) {
52
- return null;
53
- }
54
- const containerClass = depth === 1
55
- ? 'section-children ms:space-y-2'
56
- : 'section-children ms:space-y-2 ms:border-l ms:border-msborder ms:pl-3';
57
- return (_jsx("div", { className: containerClass, "data-depth": depth, children: visibleChildIds.map((childId) => (_jsx(FieldNode, { id: childId, form: form, ui: ui, depth: depth + 1 }, childId))) }));
58
- }, [field, visibleChildIds, id, form, ui, depth]);
59
- if (!field)
60
- return null;
61
- const Component = getFieldComponent(field.definition.fieldType);
62
- // Check if field is enabled/required via conditional logic
63
- const isVisible = form.getState().isVisible(field.definition.id);
64
- const isEnabled = form.getState().isEnabled(field.definition.id);
65
- const isRequired = form.getState().isRequired(field.definition.id);
66
- const response = form.getState().getResponse(field.definition.id);
67
- if (!isVisible)
68
- return null;
69
- const props = {
70
- field,
71
- form,
72
- ui,
73
- isSelected: false,
74
- isPreview: true,
75
- isEnabled,
76
- isRequired,
77
- response,
78
- onRemove: () => undefined, // No-op in renderer
79
- onUpdate: () => undefined, // No-op in renderer
80
- onResponse: (value) => form.getState().setResponse(field.definition.id, value),
81
- };
82
- const isSection = field.definition.fieldType === 'section';
83
- const parentNode = field.parentId
84
- ? form.getState().getField(field.parentId)
85
- : null;
86
- const isChildOfSection = parentNode?.definition.fieldType === 'section';
87
- const wrapperClass = `field-wrapper ms:bg-mssurface${isSection ? ' ms:mb-2 ms:border ms:border-msborder ms:rounded' : ''}${!isSection && !isChildOfSection
88
- ? ' ms:mb-2 ms:p-6 ms:border ms:border-msborder ms:rounded'
89
- : ''}${isChildOfSection
90
- ? ' ms:p-6 ms:border-b ms:border-msborder ms:last:border-b-0'
91
- : ''}${!isEnabled ? ' ms:opacity-50 ms:pointer-events-none' : ''}`;
92
- return (_jsx("div", { className: wrapperClass, "data-field-type": field.definition.fieldType, "data-field-id": field.definition.id, "aria-disabled": !isEnabled || undefined, children: field.definition.fieldType === 'section' ? ((() => {
93
- const SectionComponent = Component;
94
- return (_jsx(SectionComponent, { ...props, nestedChildren: nestedChildren }));
95
- })()) : (_jsx(Component, { ...props })) }));
96
- });
@@ -1,45 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import React from 'react';
3
- import { FieldNode } from './FieldNode.js';
4
- /**
5
- * RendererBody - Iterates over visible root fields and renders them
6
- *
7
- * Respects conditional visibility logic from form store.
8
- * Only renders fields where isVisible() returns true.
9
- * Sections recursively render their visible children.
10
- */
11
- export function RendererBody({ form, ui }) {
12
- // Subscribe to form state for visibility updates and responses
13
- const normalized = React.useSyncExternalStore((cb) => form.subscribe(cb), () => form.getState().normalized, () => form.getState().normalized);
14
- const responses = React.useSyncExternalStore((cb) => form.subscribe(cb), () => form.getState().responses, () => form.getState().responses);
15
- // Compute visible root fields
16
- const visibleRootIds = React.useMemo(() => {
17
- const cache = new Map();
18
- const isFieldRenderable = (fieldId) => {
19
- const cached = cache.get(fieldId);
20
- if (cached !== undefined)
21
- return cached;
22
- const isVisible = form.getState().isVisible(fieldId);
23
- if (!isVisible) {
24
- cache.set(fieldId, false);
25
- return false;
26
- }
27
- const node = normalized.byId[fieldId];
28
- if (!node) {
29
- cache.set(fieldId, false);
30
- return false;
31
- }
32
- // Non-section fields are renderable if visible
33
- if (node.definition.fieldType !== 'section') {
34
- cache.set(fieldId, true);
35
- return true;
36
- }
37
- // Sections are renderable only if they have at least one renderable child
38
- const hasRenderableChild = node.childIds.some((childId) => isFieldRenderable(childId));
39
- cache.set(fieldId, hasRenderableChild);
40
- return hasRenderableChild;
41
- };
42
- return normalized.rootIds.filter((id) => isFieldRenderable(id));
43
- }, [form, normalized, responses]);
44
- return (_jsx("div", { className: "canvas-fields renderer-body ms:space-y-0", children: visibleRootIds.map((id) => (_jsx(FieldNode, { id: id, form: form, ui: ui }, id))) }));
45
- }
@@ -1,2 +0,0 @@
1
- export { RendererBody } from './RendererBody.js';
2
- export { FieldNode } from './FieldNode.js';
@@ -1 +0,0 @@
1
- export { useRendererInit } from './useRendererInit.js';
@@ -1,87 +0,0 @@
1
- import React from 'react';
2
- import YAML from 'js-yaml';
3
- import { formatZodValidationError, formDefinitionSchema, } from '@esheet/core';
4
- import { importFromMcp, convertSurveyJS, isSurveyJSSchema, isMcpElicitationRequest, importFromFhir, isFhirQuestionnaire, } from '@esheet/adapters';
5
- /**
6
- * Initialize renderer with form definition.
7
- *
8
- * Auto-detects and converts the following input formats:
9
- * - eSheet FormDefinition (object or JSON/YAML string)
10
- * - FHIR R4 Questionnaire resource
11
- * - MCP elicitation/create envelope
12
- * - SurveyJS schema (has top-level `pages` or `elements` array)
13
- */
14
- export function useRendererInit(form, ui, formData, initialResponses, onValidationError, strict = false, onReady) {
15
- // Store onReady in a ref so it never causes the effect to re-run
16
- const onReadyRef = React.useRef(onReady);
17
- onReadyRef.current = onReady;
18
- React.useEffect(() => {
19
- try {
20
- // Parse input if string
21
- let parsed;
22
- if (typeof formData === 'string') {
23
- const trimmed = formData.trim();
24
- // Detect format: YAML if starts with non-brace, JSON otherwise
25
- const isYaml = !trimmed.startsWith('{') && !trimmed.startsWith('[');
26
- parsed = isYaml ? YAML.load(trimmed) : JSON.parse(trimmed);
27
- }
28
- else {
29
- parsed = formData;
30
- }
31
- // Auto-detect and convert FHIR, MCP or SurveyJS input (skipped in strict mode)
32
- if (!strict && isFhirQuestionnaire(parsed)) {
33
- parsed = importFromFhir(parsed);
34
- }
35
- else if (!strict && isMcpElicitationRequest(parsed)) {
36
- const mcpReq = parsed;
37
- if (mcpReq.params.mode !== 'url') {
38
- parsed = importFromMcp(mcpReq.params.requestedSchema, {
39
- mcpId: mcpReq.id,
40
- mcpMessage: mcpReq.params.message,
41
- });
42
- }
43
- }
44
- else if (!strict && isSurveyJSSchema(parsed)) {
45
- parsed = convertSurveyJS(parsed);
46
- }
47
- // Validate schema
48
- const validated = formDefinitionSchema.safeParse(parsed);
49
- if (!validated.success) {
50
- const errors = validated.error.issues.map(formatZodValidationError);
51
- console.error('[EsheetRenderer] Invalid form definition:', validated.error.issues);
52
- onValidationError?.(errors);
53
- // Load empty form instead of crashing
54
- form.getState().loadDefinition({
55
- id: 'invalid-form',
56
- title: 'Invalid Form',
57
- fields: [],
58
- });
59
- ui.getState().setMode('preview');
60
- return;
61
- }
62
- // Clear any previous validation errors on success
63
- onValidationError?.([]);
64
- // Load validated definition
65
- form.getState().loadDefinition(validated.data);
66
- // Apply initial responses if provided
67
- if (initialResponses && Object.keys(initialResponses).length > 0) {
68
- for (const [fieldId, value] of Object.entries(initialResponses)) {
69
- form.getState().setResponse(fieldId, value);
70
- }
71
- }
72
- // Set preview mode
73
- ui.getState().setMode('preview');
74
- onReadyRef.current?.();
75
- }
76
- catch (error) {
77
- console.error('[EsheetRenderer] Failed to initialize:', error);
78
- // Load empty form as fallback
79
- form.getState().loadDefinition({
80
- id: 'error-form',
81
- title: 'Error',
82
- fields: [],
83
- });
84
- ui.getState().setMode('preview');
85
- }
86
- }, [form, ui, formData, initialResponses, onValidationError, strict]);
87
- }
@@ -1,4 +0,0 @@
1
- export { executeToolCall } from './tool-executor.js';
2
- export { RENDERER_TOOL_DEFINITIONS } from './tool-definitions.js';
3
- export { RENDERER_SYSTEM_PROMPT } from './system-prompt.js';
4
- export { useRendererMcpToolHandler } from './useRendererToolBridge.js';
@@ -1,24 +0,0 @@
1
- export const RENDERER_SYSTEM_PROMPT = 'Form renderer assistant. You can read the current form state, inspect field values, fill in responses, and clear answers.\n\n' +
2
- 'FILL WORKFLOW:\n' +
3
- '1. Call get_form — returns {totalFields, filledCount, unfilledFields, filledFieldIds}.\n' +
4
- '2. Fill every field in unfilledFields using fill_field.\n' +
5
- '3. After each fill, check unfilledFields in the response for remaining empty fields. Fill them immediately.\n' +
6
- '4. You are done when unfilledFields is empty.\n' +
7
- 'NEVER skip a field because you are unsure of its value — generate a realistic mock value for every field including dates, times, and appointment times.\n' +
8
- 'NEVER plan all fills upfront — conditional logic reveals new fields dynamically and you must respond to unfilledFields after each fill.\n\n' +
9
- 'TEXT FIELD FORMAT RULES — each text field includes a valueFormat property; use it exactly:\n' +
10
- ' valueFormat "YYYY-MM-DD" → date, e.g. "2026-05-21"\n' +
11
- ' valueFormat "YYYY-MM-DDTHH:mm" → datetime-local, e.g. "2026-05-21T14:30"\n' +
12
- ' valueFormat "YYYY-MM" → month, e.g. "2026-05"\n' +
13
- ' valueFormat "HH:mm" → time (24-hour), e.g. "14:30"\n' +
14
- 'Wrong formats are rejected with an error — always use the valueFormat from the field schema.\n\n' +
15
- 'OTHER FIELD RULES:\n' +
16
- ' radio/dropdown/boolean/rating/slider → single string matching an option value\n' +
17
- ' check/multiselectdropdown → array of strings matching option values\n' +
18
- ' ranking → ordered array of option value strings\n' +
19
- ' multitext → array of strings, one per option slot\n' +
20
- ' singlematrix → { "Row Label": "Column Label" }\n' +
21
- ' multimatrix → { "Row Label": ["Col1", "Col2"] }\n\n' +
22
- 'Use get_form_raw to see ALL fields. Use get_form_tree for visibility/enabled/required state. ' +
23
- 'Use get_valid_response before submitting. Use clear_responses to reset. ' +
24
- 'For conversational questions reply in plain text without calling a tool.';