@mulmochat-plugin/form 0.1.1 → 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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MulmoChat Form Plugin - Core (Framework-agnostic)
3
+ *
4
+ * This module exports the core plugin logic without UI components.
5
+ * Import from "@mulmochat-plugin/form" or "@mulmochat-plugin/form/core"
6
+ */
7
+ export type { BackendType, ToolContextApp, ToolContext, ToolResult, ToolResultComplete, JsonSchemaProperty, ToolDefinition, StartApiResponse, ToolSample, InputHandler, FileInputHandler, ClipboardImageInputHandler, UrlInputHandler, TextInputHandler, FileUploadConfig, ConfigValue, ConfigFieldSchema, PluginConfigSchema, ViewComponentProps, PreviewComponentProps, ToolPluginCore, FieldType, BaseField, TextField, TextareaField, RadioField, DropdownField, CheckboxField, DateField, TimeField, NumberField, FormField, FormData, FormArgs, } from "./types";
8
+ export { TOOL_NAME, TOOL_DEFINITION, SAMPLES, executeForm, pluginCore, } from "./plugin";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * MulmoChat Form Plugin Core (Framework-agnostic)
3
+ *
4
+ * Contains the plugin logic without UI components.
5
+ * Can be used by any framework (Vue, React, etc.)
6
+ */
7
+ import type { ToolPluginCore, ToolContext, ToolResult, ToolDefinition, ToolSample, FormData, FormArgs } from "./types";
8
+ export declare const TOOL_NAME = "presentForm";
9
+ export declare const TOOL_DEFINITION: ToolDefinition;
10
+ export declare const SAMPLES: ToolSample[];
11
+ export declare const executeForm: (_context: ToolContext, args: FormArgs) => Promise<ToolResult<never, FormData>>;
12
+ export declare const pluginCore: ToolPluginCore<never, FormData, FormArgs>;
@@ -0,0 +1,311 @@
1
+ /**
2
+ * MulmoChat Plugin Core Types (Framework-agnostic)
3
+ *
4
+ * These types can be used by any framework implementation (Vue, React, etc.)
5
+ */
6
+ /**
7
+ * Backend types that plugins can declare they use.
8
+ * App layer manages actual provider/model settings for each type.
9
+ */
10
+ export type BackendType = "textLLM" | "imageGen" | "audio" | "search" | "browse" | "map" | "mulmocast";
11
+ /**
12
+ * App interface provided to plugins via context.app
13
+ * Contains backend functions and config accessors
14
+ */
15
+ export interface ToolContextApp extends Record<string, (...args: any[]) => any> {
16
+ getConfig: <T = unknown>(key: string) => T | undefined;
17
+ setConfig: (key: string, value: unknown) => void;
18
+ }
19
+ /**
20
+ * Context passed to plugin execute function
21
+ */
22
+ export interface ToolContext {
23
+ currentResult?: ToolResult<unknown> | null;
24
+ app?: ToolContextApp;
25
+ }
26
+ /**
27
+ * Result returned from plugin execution
28
+ */
29
+ export interface ToolResult<T = unknown, J = unknown> {
30
+ toolName?: string;
31
+ uuid?: string;
32
+ message: string;
33
+ title?: string;
34
+ jsonData?: J;
35
+ instructions?: string;
36
+ instructionsRequired?: boolean;
37
+ updating?: boolean;
38
+ cancelled?: boolean;
39
+ data?: T;
40
+ viewState?: Record<string, unknown>;
41
+ }
42
+ /**
43
+ * Complete tool result with required fields
44
+ */
45
+ export interface ToolResultComplete<T = unknown, J = unknown> extends ToolResult<T, J> {
46
+ toolName: string;
47
+ uuid: string;
48
+ }
49
+ /**
50
+ * JSON Schema property definition for tool parameters
51
+ */
52
+ export interface JsonSchemaProperty {
53
+ type?: string;
54
+ description?: string;
55
+ enum?: string[];
56
+ items?: JsonSchemaProperty;
57
+ minimum?: number;
58
+ maximum?: number;
59
+ minItems?: number;
60
+ maxItems?: number;
61
+ properties?: Record<string, JsonSchemaProperty>;
62
+ required?: string[];
63
+ additionalProperties?: boolean;
64
+ oneOf?: JsonSchemaProperty[];
65
+ [key: string]: unknown;
66
+ }
67
+ /**
68
+ * Tool definition for OpenAI-compatible function calling
69
+ */
70
+ export interface ToolDefinition {
71
+ type: "function";
72
+ name: string;
73
+ description: string;
74
+ parameters?: {
75
+ type: "object";
76
+ properties: Record<string, JsonSchemaProperty>;
77
+ required: string[];
78
+ additionalProperties?: boolean;
79
+ };
80
+ }
81
+ /**
82
+ * API response from server start endpoint
83
+ */
84
+ export interface StartApiResponse {
85
+ hasOpenAIApiKey?: boolean;
86
+ hasAnthropicApiKey?: boolean;
87
+ hasGoogleApiKey?: boolean;
88
+ [key: string]: unknown;
89
+ }
90
+ /**
91
+ * Sample arguments for testing
92
+ */
93
+ export interface ToolSample {
94
+ name: string;
95
+ args: Record<string, unknown>;
96
+ }
97
+ /**
98
+ * File input handler
99
+ */
100
+ export interface FileInputHandler {
101
+ type: "file";
102
+ acceptedTypes: string[];
103
+ handleInput: (fileData: string, fileName: string) => ToolResult<unknown, unknown>;
104
+ }
105
+ /**
106
+ * Clipboard image input handler
107
+ */
108
+ export interface ClipboardImageInputHandler {
109
+ type: "clipboard-image";
110
+ handleInput: (imageData: string) => ToolResult<unknown, unknown>;
111
+ }
112
+ /**
113
+ * URL input handler
114
+ */
115
+ export interface UrlInputHandler {
116
+ type: "url";
117
+ patterns?: string[];
118
+ handleInput: (url: string) => ToolResult<unknown, unknown>;
119
+ }
120
+ /**
121
+ * Text input handler
122
+ */
123
+ export interface TextInputHandler {
124
+ type: "text";
125
+ patterns?: string[];
126
+ handleInput: (text: string) => ToolResult<unknown, unknown>;
127
+ }
128
+ /**
129
+ * Union of all input handler types
130
+ */
131
+ export type InputHandler = FileInputHandler | ClipboardImageInputHandler | UrlInputHandler | TextInputHandler;
132
+ /**
133
+ * Legacy file upload config (for backward compatibility)
134
+ * @deprecated Use InputHandler instead
135
+ */
136
+ export interface FileUploadConfig {
137
+ acceptedTypes: string[];
138
+ handleUpload: (fileData: string, fileName: string, ...args: unknown[]) => ToolResult<unknown, unknown>;
139
+ }
140
+ export type ConfigValue = string | number | boolean | string[];
141
+ interface BaseFieldSchema {
142
+ label: string;
143
+ description?: string;
144
+ required?: boolean;
145
+ }
146
+ export interface StringFieldSchema extends BaseFieldSchema {
147
+ type: "string";
148
+ placeholder?: string;
149
+ minLength?: number;
150
+ maxLength?: number;
151
+ pattern?: string;
152
+ }
153
+ export interface NumberFieldSchema extends BaseFieldSchema {
154
+ type: "number";
155
+ min?: number;
156
+ max?: number;
157
+ step?: number;
158
+ }
159
+ export interface BooleanFieldSchema extends BaseFieldSchema {
160
+ type: "boolean";
161
+ }
162
+ export interface SelectOption {
163
+ value: string;
164
+ label: string;
165
+ description?: string;
166
+ disabled?: boolean;
167
+ }
168
+ export interface SelectFieldSchema extends BaseFieldSchema {
169
+ type: "select";
170
+ options: SelectOption[];
171
+ }
172
+ export interface MultiSelectFieldSchema extends BaseFieldSchema {
173
+ type: "multiselect";
174
+ options: SelectOption[];
175
+ minItems?: number;
176
+ maxItems?: number;
177
+ }
178
+ export type ConfigFieldSchema = StringFieldSchema | NumberFieldSchema | BooleanFieldSchema | SelectFieldSchema | MultiSelectFieldSchema;
179
+ /**
180
+ * Plugin configuration schema (JSON Schema based)
181
+ */
182
+ export interface PluginConfigSchema {
183
+ key: string;
184
+ defaultValue: ConfigValue;
185
+ schema: ConfigFieldSchema;
186
+ }
187
+ /**
188
+ * Standard props for View components
189
+ */
190
+ export interface ViewComponentProps<T = unknown, J = unknown> {
191
+ selectedResult: ToolResultComplete<T, J>;
192
+ sendTextMessage: (text?: string) => void;
193
+ onUpdateResult?: (result: Partial<ToolResult<T, J>>) => void;
194
+ pluginConfigs?: Record<string, unknown>;
195
+ }
196
+ /**
197
+ * Standard props for Preview components
198
+ */
199
+ export interface PreviewComponentProps<T = unknown, J = unknown> {
200
+ result: ToolResultComplete<T, J>;
201
+ isSelected?: boolean;
202
+ onSelect?: () => void;
203
+ }
204
+ /**
205
+ * Core plugin interface - framework agnostic
206
+ * Does not include UI components
207
+ */
208
+ export interface ToolPluginCore<T = unknown, J = unknown, A extends object = object> {
209
+ toolDefinition: ToolDefinition;
210
+ execute: (context: ToolContext, args: A) => Promise<ToolResult<T, J>>;
211
+ generatingMessage: string;
212
+ waitingMessage?: string;
213
+ uploadMessage?: string;
214
+ isEnabled: (startResponse?: StartApiResponse | null) => boolean;
215
+ delayAfterExecution?: number;
216
+ systemPrompt?: string;
217
+ inputHandlers?: InputHandler[];
218
+ /** @deprecated Use inputHandlers instead */
219
+ fileUpload?: FileUploadConfig;
220
+ /** New JSON Schema based config (framework-agnostic) */
221
+ configSchema?: PluginConfigSchema;
222
+ samples?: ToolSample[];
223
+ backends?: BackendType[];
224
+ }
225
+ /** Field type discriminator */
226
+ export type FieldType = "text" | "textarea" | "radio" | "dropdown" | "checkbox" | "date" | "time" | "number";
227
+ /** Base field interface */
228
+ export interface BaseField {
229
+ id: string;
230
+ type: FieldType;
231
+ label: string;
232
+ description?: string;
233
+ required?: boolean;
234
+ maxLength?: number;
235
+ }
236
+ /** Text field */
237
+ export interface TextField extends BaseField {
238
+ type: "text";
239
+ placeholder?: string;
240
+ validation?: "email" | "url" | "phone" | string;
241
+ defaultValue?: string;
242
+ minLength?: number;
243
+ maxLength?: number;
244
+ }
245
+ /** Textarea field */
246
+ export interface TextareaField extends BaseField {
247
+ type: "textarea";
248
+ placeholder?: string;
249
+ minLength?: number;
250
+ maxLength?: number;
251
+ rows?: number;
252
+ defaultValue?: string;
253
+ }
254
+ /** Radio field */
255
+ export interface RadioField extends BaseField {
256
+ type: "radio";
257
+ choices: string[];
258
+ defaultValue?: string;
259
+ }
260
+ /** Dropdown field */
261
+ export interface DropdownField extends BaseField {
262
+ type: "dropdown";
263
+ choices: string[];
264
+ searchable?: boolean;
265
+ defaultValue?: string;
266
+ }
267
+ /** Checkbox field */
268
+ export interface CheckboxField extends BaseField {
269
+ type: "checkbox";
270
+ choices: string[];
271
+ minSelections?: number;
272
+ maxSelections?: number;
273
+ defaultValue?: string[];
274
+ }
275
+ /** Date field */
276
+ export interface DateField extends BaseField {
277
+ type: "date";
278
+ minDate?: string;
279
+ maxDate?: string;
280
+ format?: string;
281
+ defaultValue?: string;
282
+ }
283
+ /** Time field */
284
+ export interface TimeField extends BaseField {
285
+ type: "time";
286
+ format?: "12hr" | "24hr";
287
+ defaultValue?: string;
288
+ }
289
+ /** Number field */
290
+ export interface NumberField extends BaseField {
291
+ type: "number";
292
+ min?: number;
293
+ max?: number;
294
+ step?: number;
295
+ defaultValue?: number;
296
+ }
297
+ /** Union type for all fields */
298
+ export type FormField = TextField | TextareaField | RadioField | DropdownField | CheckboxField | DateField | TimeField | NumberField;
299
+ /** Form data stored in result.jsonData */
300
+ export interface FormData {
301
+ title?: string;
302
+ description?: string;
303
+ fields: FormField[];
304
+ }
305
+ /** Arguments passed to the form tool */
306
+ export interface FormArgs {
307
+ title?: string;
308
+ description?: string;
309
+ fields: FormField[];
310
+ }
311
+ export {};
package/dist/core.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n="presentForm",s={type:"function",name:n,description:"Create a structured form to collect information from the user. Supports various field types including text input, textarea, multiple choice (radio), dropdown menus, checkboxes, date/time pickers, and number inputs. Each field can have validation rules and help text.",parameters:{type:"object",properties:{title:{type:"string",description:"Optional title for the form (e.g., 'User Registration')"},description:{type:"string",description:"Optional description explaining the purpose of the form"},fields:{type:"array",description:"Array of form fields with various types and configurations",items:{type:"object",properties:{id:{type:"string",description:"Unique identifier for the field (e.g., 'email', 'birthdate'). This will be the key in the JSON response. Use descriptive camelCase or snake_case names."},type:{type:"string",enum:["text","textarea","radio","dropdown","checkbox","date","time","number"],description:"Field type: 'text' for short text, 'textarea' for long text, 'radio' for 2-6 choices, 'dropdown' for many choices, 'checkbox' for multiple selections, 'date' for date picker, 'time' for time picker, 'number' for numeric input"},label:{type:"string",description:"Field label shown to the user"},description:{type:"string",description:"Optional help text explaining the field"},required:{type:"boolean",description:"Whether the field is required (default: false)"},placeholder:{type:"string",description:"Placeholder text for text/textarea fields"},validation:{type:"string",description:"For text fields: 'email', 'url', 'phone', or a regex pattern"},minLength:{type:"number",description:"Minimum character length for textarea fields"},maxLength:{type:"number",description:"Maximum character length for textarea fields"},rows:{type:"number",description:"Number of visible rows for textarea (default: 4)"},choices:{type:"array",items:{type:"string"},description:"Array of choices for radio/dropdown/checkbox fields. Radio should have 2-6 choices, dropdown for 7+ choices."},searchable:{type:"boolean",description:"Make dropdown searchable (for large lists)"},minSelections:{type:"number",description:"Minimum number of selections for checkbox fields"},maxSelections:{type:"number",description:"Maximum number of selections for checkbox fields"},minDate:{type:"string",description:"Minimum date (ISO format: YYYY-MM-DD)"},maxDate:{type:"string",description:"Maximum date (ISO format: YYYY-MM-DD)"},format:{type:"string",description:"Format for time fields: '12hr' or '24hr'"},min:{type:"number",description:"Minimum value for number fields"},max:{type:"number",description:"Maximum value for number fields"},step:{type:"number",description:"Step increment for number fields"},defaultValue:{description:"Optional default/pre-filled value for the field. Type varies by field: string for text/textarea/radio/dropdown/date/time, number for number fields, array of strings for checkbox fields. For radio/dropdown, must be one of the choices. For checkbox, must be a subset of choices."}},required:["id","type","label"]},minItems:1}},required:["fields"]}},l=[{name:"Contact Form",args:{title:"Contact Us",description:"Please fill out the form below to get in touch.",fields:[{id:"name",type:"text",label:"Full Name",required:!0,placeholder:"John Doe"},{id:"email",type:"text",label:"Email Address",required:!0,placeholder:"john@example.com",validation:"email"},{id:"subject",type:"dropdown",label:"Subject",choices:["General Inquiry","Technical Support","Sales","Feedback"],required:!0},{id:"message",type:"textarea",label:"Message",required:!0,minLength:10,maxLength:500,rows:5}]}},{name:"Survey Form",args:{title:"Customer Satisfaction Survey",fields:[{id:"satisfaction",type:"radio",label:"How satisfied are you with our service?",choices:["Very Satisfied","Satisfied","Neutral","Dissatisfied","Very Dissatisfied"],required:!0},{id:"features",type:"checkbox",label:"Which features do you use most?",choices:["Dashboard","Reports","Analytics","API","Integrations"],minSelections:1,maxSelections:3},{id:"recommendation",type:"number",label:"How likely are you to recommend us? (0-10)",min:0,max:10,step:1}]}},{name:"Event Registration",args:{title:"Event Registration",description:"Register for our upcoming conference.",fields:[{id:"attendeeName",type:"text",label:"Attendee Name",required:!0},{id:"eventDate",type:"date",label:"Preferred Date",required:!0,minDate:"2025-01-01",maxDate:"2025-12-31"},{id:"sessionTime",type:"time",label:"Session Time",format:"12hr"},{id:"dietaryRestrictions",type:"checkbox",label:"Dietary Restrictions",choices:["Vegetarian","Vegan","Gluten-Free","Halal","Kosher"]}]}}],d=async(g,c)=>{try{const{title:i,description:u,fields:t}=c;if(!t||!Array.isArray(t)||t.length===0)throw new Error("At least one field is required");const o=new Set;for(let r=0;r<t.length;r++){const e=t[r];if(!e.id||typeof e.id!="string")throw new Error(`Field ${r+1} must have a valid 'id' property`);if(!e.type||typeof e.type!="string")throw new Error(`Field ${r+1} must have a valid 'type' property`);if(!e.label||typeof e.label!="string")throw new Error(`Field ${r+1} must have a valid 'label' property`);if(o.has(e.id))throw new Error(`Duplicate field ID: '${e.id}'`);switch(o.add(e.id),e.type){case"text":case"textarea":if(e.minLength!==void 0&&e.maxLength!==void 0&&e.minLength>e.maxLength)throw new Error(`Field '${e.id}': minLength cannot be greater than maxLength`);break;case"radio":if(!Array.isArray(e.choices)||e.choices.length<2)throw new Error(`Field '${e.id}': radio fields must have at least 2 choices`);e.choices.length>6&&console.warn(`Field '${e.id}': radio fields with more than 6 choices should use 'dropdown' type instead`);break;case"dropdown":case"checkbox":if(!Array.isArray(e.choices)||e.choices.length<1)throw new Error(`Field '${e.id}': ${e.type} fields must have at least 1 choice`);break;case"number":if(e.min!==void 0&&e.max!==void 0&&e.min>e.max)throw new Error(`Field '${e.id}': min cannot be greater than max`);break;case"date":if(e.minDate&&e.maxDate&&e.minDate>e.maxDate)throw new Error(`Field '${e.id}': minDate cannot be after maxDate`);break;case"time":break;default:{const a=e;throw new Error(`Field '${a.id}': unknown field type '${a.type}'`)}}if(e.type==="checkbox"){if(e.minSelections!==void 0&&e.maxSelections!==void 0&&e.minSelections>e.maxSelections)throw new Error(`Field '${e.id}': minSelections cannot be greater than maxSelections`);if(e.maxSelections!==void 0&&e.maxSelections>e.choices.length)throw new Error(`Field '${e.id}': maxSelections cannot exceed number of choices`)}if(e.defaultValue!==void 0)switch(e.type){case"text":case"textarea":if(typeof e.defaultValue!="string")throw new Error(`Field '${e.id}': defaultValue must be a string`);if(e.minLength!==void 0&&e.defaultValue.length<e.minLength)throw new Error(`Field '${e.id}': defaultValue length is less than minLength`);if(e.maxLength!==void 0&&e.defaultValue.length>e.maxLength)throw new Error(`Field '${e.id}': defaultValue length exceeds maxLength`);break;case"radio":case"dropdown":if(typeof e.defaultValue!="string")throw new Error(`Field '${e.id}': defaultValue must be a string`);if(!e.choices.includes(e.defaultValue))throw new Error(`Field '${e.id}': defaultValue '${e.defaultValue}' is not in choices`);break;case"checkbox":if(!Array.isArray(e.defaultValue))throw new Error(`Field '${e.id}': defaultValue must be an array`);for(const a of e.defaultValue)if(!e.choices.includes(a))throw new Error(`Field '${e.id}': defaultValue contains '${a}' which is not in choices`);if(e.minSelections!==void 0&&e.defaultValue.length<e.minSelections)throw new Error(`Field '${e.id}': defaultValue has fewer selections than minSelections`);if(e.maxSelections!==void 0&&e.defaultValue.length>e.maxSelections)throw new Error(`Field '${e.id}': defaultValue has more selections than maxSelections`);break;case"number":if(typeof e.defaultValue!="number")throw new Error(`Field '${e.id}': defaultValue must be a number`);if(e.min!==void 0&&e.defaultValue<e.min)throw new Error(`Field '${e.id}': defaultValue is less than min`);if(e.max!==void 0&&e.defaultValue>e.max)throw new Error(`Field '${e.id}': defaultValue is greater than max`);break;case"date":if(typeof e.defaultValue!="string")throw new Error(`Field '${e.id}': defaultValue must be a string (ISO date format)`);if(e.minDate!==void 0&&e.defaultValue<e.minDate)throw new Error(`Field '${e.id}': defaultValue is before minDate`);if(e.maxDate!==void 0&&e.defaultValue>e.maxDate)throw new Error(`Field '${e.id}': defaultValue is after maxDate`);break;case"time":if(typeof e.defaultValue!="string")throw new Error(`Field '${e.id}': defaultValue must be a string`);break}}const f={title:i,description:u,fields:t},m=`${t.length} field${t.length>1?"s":""}`,h=i?`: ${i}`:"";return{message:`Form created with ${m}${h}`,jsonData:f,instructions:"The form has been presented to the user. Wait for the user to fill out and submit the form. They will send their responses as a JSON message."}}catch(i){return console.error(`ERR: exception
2
+ Form creation error`,i),{message:`Form error: ${i instanceof Error?i.message:"Unknown error"}`,instructions:"Acknowledge that there was an error creating the form and suggest trying again with corrected field definitions."}}},p={toolDefinition:s,execute:d,generatingMessage:"Preparing form...",isEnabled:()=>!0,samples:l};exports.SAMPLES=l;exports.TOOL_DEFINITION=s;exports.TOOL_NAME=n;exports.executeForm=d;exports.pluginCore=p;