(
formTree: FieldTree<unknown>,
options: {name: string; description: string},
injector: Injector,
)
| 34 | }; |
| 35 | |
| 36 | function initWebMcpForm( |
| 37 | formTree: FieldTree<unknown>, |
| 38 | options: {name: string; description: string}, |
| 39 | injector: Injector, |
| 40 | ) { |
| 41 | const node = formTree() as FieldNode; |
| 42 | const inputSchema = inferSchemaFromFieldNode(node); |
| 43 | |
| 44 | if (!inputSchema) { |
| 45 | throw new Error( |
| 46 | `Could not accurately infer WebMCP schema for form "${options.name}". ` + |
| 47 | `Ensure that the form model does not contain null, undefined, empty arrays, or unsupported types.`, |
| 48 | ); |
| 49 | } |
| 50 | |
| 51 | declareExperimentalWebMcpTool( |
| 52 | { |
| 53 | name: options.name, |
| 54 | description: options.description, |
| 55 | inputSchema, |
| 56 | execute: async (args: Record<string, unknown>) => { |
| 57 | // Populate the form with changes from the agent. |
| 58 | node.value.set(args); |
| 59 | |
| 60 | // Trigger form submission. |
| 61 | const success = await submit(formTree); |
| 62 | |
| 63 | // Report the result to the agent. |
| 64 | if (success) { |
| 65 | return {content: [{type: 'text', text: 'Form submitted successfully.'}]}; |
| 66 | } else { |
| 67 | const errorMessages = node |
| 68 | .errorSummary() |
| 69 | .map((err) => { |
| 70 | const fieldName = (err.fieldTree() as FieldNode).structure.pathKeys().join('.'); |
| 71 | return `${fieldName ? `${fieldName}: ` : ''}${err.message || err.kind}`; |
| 72 | }) |
| 73 | .join('\n'); |
| 74 | return {content: [{type: 'text', text: `Form submission failed:\n${errorMessages}`}]}; |
| 75 | } |
| 76 | }, |
| 77 | }, |
| 78 | injector, |
| 79 | ); |
| 80 | } |
| 81 | |
| 82 | /** Infers the JSON schema from a specific form field. */ |
| 83 | function inferSchemaFromFieldNode(node: FieldNode): JsonSchemaForInference | undefined { |
no test coverage detected