auto-webmcp 0.3.17 → 0.3.18

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.
@@ -14,6 +14,7 @@ function resolveConfig(userConfig) {
14
14
  timeoutMs: Math.max(100, userConfig?.execution?.timeoutMs ?? 15e3)
15
15
  },
16
16
  overrides: userConfig?.overrides ?? {},
17
+ preserveExisting: userConfig?.preserveExisting ?? false,
17
18
  debug: userConfig?.debug ?? false
18
19
  };
19
20
  }
@@ -973,6 +974,53 @@ function buildSchemaFromInputs(inputs) {
973
974
  }
974
975
 
975
976
  // src/registry.ts
977
+ var EXECUTE_OUTPUT_SCHEMA = {
978
+ type: "object",
979
+ properties: {
980
+ status: {
981
+ type: "string",
982
+ enum: ["success", "partial", "error", "awaiting_user_action", "timed_out", "blocked_invalid"],
983
+ description: "Outcome of the form execution."
984
+ },
985
+ filled_fields: {
986
+ type: "object",
987
+ description: "Field name to submitted value map."
988
+ },
989
+ skipped_fields: {
990
+ type: "array",
991
+ items: { type: "string" },
992
+ description: "Fields the agent provided but that could not be filled."
993
+ },
994
+ missing_required: {
995
+ type: "array",
996
+ items: { type: "string" },
997
+ description: "Required fields not supplied by the agent."
998
+ },
999
+ validation_errors: {
1000
+ type: "array",
1001
+ items: {
1002
+ type: "object",
1003
+ properties: {
1004
+ field: { type: "string" },
1005
+ constraint: { type: "string", description: "HTML ValidityState key that failed." },
1006
+ message: { type: "string" }
1007
+ },
1008
+ required: ["field", "constraint", "message"]
1009
+ },
1010
+ description: "Per-field HTML5 validation failures (present when status is blocked_invalid)."
1011
+ },
1012
+ existing_values: {
1013
+ type: "object",
1014
+ description: "Field values present in the form before the agent filled it."
1015
+ },
1016
+ warnings: {
1017
+ type: "array",
1018
+ items: { type: "object" },
1019
+ description: "Non-fatal fill warnings (alias_resolved, clamped, not_filled, etc.)."
1020
+ }
1021
+ },
1022
+ required: ["status", "filled_fields", "skipped_fields", "missing_required", "warnings"]
1023
+ };
976
1024
  var registeredTools = /* @__PURE__ */ new Map();
977
1025
  var registrationControllers = /* @__PURE__ */ new Map();
978
1026
  function isWebMCPSupported() {
@@ -989,6 +1037,7 @@ async function registerFormTool(form, metadata, execute) {
989
1037
  name: metadata.name,
990
1038
  description: metadata.description,
991
1039
  inputSchema: metadata.inputSchema,
1040
+ outputSchema: EXECUTE_OUTPUT_SCHEMA,
992
1041
  execute
993
1042
  };
994
1043
  if (metadata.annotations && Object.keys(metadata.annotations).length > 0) {
@@ -1042,6 +1091,7 @@ var formFieldElements = /* @__PURE__ */ new WeakMap();
1042
1091
  var pendingWarnings = /* @__PURE__ */ new WeakMap();
1043
1092
  var pendingFillWarnings = /* @__PURE__ */ new WeakMap();
1044
1093
  var lastFilledSnapshot = /* @__PURE__ */ new WeakMap();
1094
+ var preFillValues = /* @__PURE__ */ new WeakMap();
1045
1095
  var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
1046
1096
  var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
1047
1097
  var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
@@ -1133,6 +1183,36 @@ function collectInvalidFieldWarnings(form) {
1133
1183
  }
1134
1184
  return warnings;
1135
1185
  }
1186
+ function captureCurrentValues(form) {
1187
+ const result = {};
1188
+ try {
1189
+ const data = new FormData(form);
1190
+ for (const [key, val] of data.entries()) {
1191
+ if (result[key] !== void 0) {
1192
+ const existing = result[key];
1193
+ result[key] = Array.isArray(existing) ? [...existing, val] : [existing, val];
1194
+ } else {
1195
+ result[key] = val;
1196
+ }
1197
+ }
1198
+ } catch {
1199
+ }
1200
+ return result;
1201
+ }
1202
+ function collectValidationErrors(form) {
1203
+ const errors = [];
1204
+ for (const control of Array.from(form.elements)) {
1205
+ if (!(control instanceof HTMLInputElement) && !(control instanceof HTMLTextAreaElement) && !(control instanceof HTMLSelectElement))
1206
+ continue;
1207
+ if (!control.willValidate || control.checkValidity())
1208
+ continue;
1209
+ const field = control.name || control.id || control.getAttribute("aria-label") || "unknown_field";
1210
+ const v = control.validity;
1211
+ const constraint = v.valueMissing ? "valueMissing" : v.typeMismatch ? "typeMismatch" : v.patternMismatch ? "patternMismatch" : v.tooLong ? "tooLong" : v.tooShort ? "tooShort" : v.rangeUnderflow ? "rangeUnderflow" : v.rangeOverflow ? "rangeOverflow" : v.stepMismatch ? "stepMismatch" : v.customError ? "customError" : "badInput";
1212
+ errors.push({ field, constraint, message: control.validationMessage || `field "${field}" failed validation` });
1213
+ }
1214
+ return errors;
1215
+ }
1136
1216
  function buildExecuteHandler(form, config, toolName, metadata) {
1137
1217
  if (metadata?.fieldElements) {
1138
1218
  formFieldElements.set(form, metadata.fieldElements);
@@ -1154,6 +1234,8 @@ function buildExecuteHandler(form, config, toolName, metadata) {
1154
1234
  }
1155
1235
  pendingFillWarnings.set(form, []);
1156
1236
  pendingWarnings.delete(form);
1237
+ const existingSnapshot = captureCurrentValues(form);
1238
+ preFillValues.set(form, existingSnapshot);
1157
1239
  const { resolved: resolvedParams, warnings: aliasWarnings } = resolveParamsForSchema(
1158
1240
  form,
1159
1241
  params,
@@ -1163,7 +1245,28 @@ function buildExecuteHandler(form, config, toolName, metadata) {
1163
1245
  if (aliasWarnings.length > 0) {
1164
1246
  pendingFillWarnings.set(form, [...pendingFillWarnings.get(form) ?? [], ...aliasWarnings]);
1165
1247
  }
1166
- fillFormFields(form, resolvedParams);
1248
+ let paramsToFill = resolvedParams;
1249
+ if (config.preserveExisting) {
1250
+ const preserved = [];
1251
+ paramsToFill = Object.fromEntries(
1252
+ Object.entries(resolvedParams).filter(([key]) => {
1253
+ const current = existingSnapshot[key];
1254
+ const hasValue = current !== void 0 && current !== "" && current !== null;
1255
+ if (hasValue) {
1256
+ preserved.push({
1257
+ field: key,
1258
+ type: "not_filled",
1259
+ message: `field "${key}" already has a value and preserveExisting is enabled`
1260
+ });
1261
+ }
1262
+ return !hasValue;
1263
+ })
1264
+ );
1265
+ if (preserved.length > 0) {
1266
+ pendingFillWarnings.set(form, [...pendingFillWarnings.get(form) ?? [], ...preserved]);
1267
+ }
1268
+ }
1269
+ fillFormFields(form, paramsToFill);
1167
1270
  const missingNow = getMissingRequired(metadata, resolvedParams);
1168
1271
  if (missingNow.length > 0)
1169
1272
  pendingWarnings.set(form, missingNow);
@@ -1181,16 +1284,19 @@ function buildExecuteHandler(form, config, toolName, metadata) {
1181
1284
  type: "timeout",
1182
1285
  message: timedOutState === "timed_out" ? `tool execution timed out after ${timeoutMs}ms` : `waiting for user submit (timed out after ${timeoutMs}ms)`
1183
1286
  };
1287
+ const _existingValsTimeout = preFillValues.get(form);
1184
1288
  const structured = {
1185
1289
  status: timedOutState,
1186
1290
  filled_fields: serializeFormData(form, lastParams.get(form), formFieldElements.get(form)),
1187
1291
  skipped_fields: [],
1188
1292
  missing_required: pendingWarnings.get(form) ?? [],
1189
- warnings: [...pendingFillWarnings.get(form) ?? [], warn]
1293
+ warnings: [...pendingFillWarnings.get(form) ?? [], warn],
1294
+ ..._existingValsTimeout !== void 0 && { existing_values: _existingValsTimeout }
1190
1295
  };
1191
1296
  pendingWarnings.delete(form);
1192
1297
  pendingFillWarnings.delete(form);
1193
1298
  lastFilledSnapshot.delete(form);
1299
+ preFillValues.delete(form);
1194
1300
  resolve({
1195
1301
  content: [
1196
1302
  { type: "text", text: warn.message },
@@ -1241,17 +1347,21 @@ function buildExecuteHandler(form, config, toolName, metadata) {
1241
1347
  ];
1242
1348
  pendingFillWarnings.delete(submitForm);
1243
1349
  pendingFillWarnings.delete(form);
1350
+ const _existingValsBlocked = preFillValues.get(form);
1244
1351
  const structured = {
1245
1352
  status: "blocked_invalid",
1246
1353
  filled_fields: serializeFormData(submitForm, lastParams.get(submitForm) ?? lastParams.get(form), formFieldElements.get(submitForm) ?? formFieldElements.get(form)),
1247
1354
  skipped_fields: [],
1248
1355
  missing_required: pendingWarnings.get(submitForm) ?? pendingWarnings.get(form) ?? [],
1249
- warnings
1356
+ warnings,
1357
+ validation_errors: collectValidationErrors(submitForm),
1358
+ ..._existingValsBlocked !== void 0 && { existing_values: _existingValsBlocked }
1250
1359
  };
1251
1360
  pendingWarnings.delete(submitForm);
1252
1361
  pendingWarnings.delete(form);
1253
1362
  lastFilledSnapshot.delete(submitForm);
1254
1363
  lastFilledSnapshot.delete(form);
1364
+ preFillValues.delete(form);
1255
1365
  resolve({
1256
1366
  content: [
1257
1367
  { type: "text", text: "Form submission blocked by native validation." },
@@ -1283,7 +1393,9 @@ function attachSubmitInterceptor(form, toolName) {
1283
1393
  clearTimeout(pending.timeoutId);
1284
1394
  pendingExecutions.delete(form);
1285
1395
  const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
1396
+ const existingVals = preFillValues.get(form);
1286
1397
  lastFilledSnapshot.delete(form);
1398
+ preFillValues.delete(form);
1287
1399
  const missingRequired = pendingWarnings.get(form) ?? [];
1288
1400
  pendingWarnings.delete(form);
1289
1401
  const fillWarnings = pendingFillWarnings.get(form) ?? [];
@@ -1301,7 +1413,8 @@ function attachSubmitInterceptor(form, toolName) {
1301
1413
  message: `required field "${f}" was not provided`
1302
1414
  })),
1303
1415
  ...fillWarnings
1304
- ]
1416
+ ],
1417
+ ...existingVals !== void 0 && { existing_values: existingVals }
1305
1418
  };
1306
1419
  const allWarnMessages = [
1307
1420
  ...missingRequired.length ? [`required fields were not filled: ${missingRequired.join(", ")}`] : [],
@@ -1323,6 +1436,7 @@ function attachSubmitInterceptor(form, toolName) {
1323
1436
  });
1324
1437
  form.addEventListener("reset", () => {
1325
1438
  lastFilledSnapshot.delete(form);
1439
+ preFillValues.delete(form);
1326
1440
  window.dispatchEvent(new CustomEvent("toolcancel", { detail: { toolName } }));
1327
1441
  });
1328
1442
  }