markform 0.0.1 → 0.1.1

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.
@@ -30,6 +30,7 @@ const CheckboxModeSchema = z.enum([
30
30
  "explicit"
31
31
  ]);
32
32
  const FillModeSchema = z.enum(["continue", "overwrite"]);
33
+ const MockModeSchema = z.enum(["mock", "live"]);
33
34
  const ApprovalModeSchema = z.enum(["none", "blocking"]);
34
35
  const FieldKindSchema = z.enum([
35
36
  "string",
@@ -37,7 +38,9 @@ const FieldKindSchema = z.enum([
37
38
  "string_list",
38
39
  "checkboxes",
39
40
  "single_select",
40
- "multi_select"
41
+ "multi_select",
42
+ "url",
43
+ "url_list"
41
44
  ]);
42
45
  const FieldPriorityLevelSchema = z.enum([
43
46
  "high",
@@ -100,13 +103,26 @@ const MultiSelectFieldSchema = z.object({
100
103
  minSelections: z.number().int().nonnegative().optional(),
101
104
  maxSelections: z.number().int().nonnegative().optional()
102
105
  });
106
+ const UrlFieldSchema = z.object({
107
+ ...FieldBaseSchemaPartial,
108
+ kind: z.literal("url")
109
+ });
110
+ const UrlListFieldSchema = z.object({
111
+ ...FieldBaseSchemaPartial,
112
+ kind: z.literal("url_list"),
113
+ minItems: z.number().int().nonnegative().optional(),
114
+ maxItems: z.number().int().nonnegative().optional(),
115
+ uniqueItems: z.boolean().optional()
116
+ });
103
117
  const FieldSchema = z.discriminatedUnion("kind", [
104
118
  StringFieldSchema,
105
119
  NumberFieldSchema,
106
120
  StringListFieldSchema,
107
121
  CheckboxesFieldSchema,
108
122
  SingleSelectFieldSchema,
109
- MultiSelectFieldSchema
123
+ MultiSelectFieldSchema,
124
+ UrlFieldSchema,
125
+ UrlListFieldSchema
110
126
  ]);
111
127
  const FieldGroupSchema = z.object({
112
128
  kind: z.literal("field_group"),
@@ -144,13 +160,23 @@ const MultiSelectValueSchema = z.object({
144
160
  kind: z.literal("multi_select"),
145
161
  selected: z.array(OptionIdSchema)
146
162
  });
163
+ const UrlValueSchema = z.object({
164
+ kind: z.literal("url"),
165
+ value: z.string().nullable()
166
+ });
167
+ const UrlListValueSchema = z.object({
168
+ kind: z.literal("url_list"),
169
+ items: z.array(z.string())
170
+ });
147
171
  const FieldValueSchema = z.discriminatedUnion("kind", [
148
172
  StringValueSchema,
149
173
  NumberValueSchema,
150
174
  StringListValueSchema,
151
175
  CheckboxesValueSchema,
152
176
  SingleSelectValueSchema,
153
- MultiSelectValueSchema
177
+ MultiSelectValueSchema,
178
+ UrlValueSchema,
179
+ UrlListValueSchema
154
180
  ]);
155
181
  const DocumentationTagSchema = z.enum([
156
182
  "description",
@@ -240,7 +266,9 @@ const FieldProgressSchema = z.object({
240
266
  state: ProgressStateSchema,
241
267
  valid: z.boolean(),
242
268
  issueCount: z.number().int().nonnegative(),
243
- checkboxProgress: CheckboxProgressCountsSchema.optional()
269
+ checkboxProgress: CheckboxProgressCountsSchema.optional(),
270
+ skipped: z.boolean(),
271
+ skipReason: z.string().optional()
244
272
  });
245
273
  const ProgressCountsSchema = z.object({
246
274
  totalFields: z.number().int().nonnegative(),
@@ -250,7 +278,9 @@ const ProgressCountsSchema = z.object({
250
278
  incompleteFields: z.number().int().nonnegative(),
251
279
  invalidFields: z.number().int().nonnegative(),
252
280
  emptyRequiredFields: z.number().int().nonnegative(),
253
- emptyOptionalFields: z.number().int().nonnegative()
281
+ emptyOptionalFields: z.number().int().nonnegative(),
282
+ answeredFields: z.number().int().nonnegative(),
283
+ skippedFields: z.number().int().nonnegative()
254
284
  });
255
285
  const ProgressSummarySchema = z.object({
256
286
  counts: ProgressCountsSchema,
@@ -313,10 +343,25 @@ const SetMultiSelectPatchSchema = z.object({
313
343
  fieldId: IdSchema,
314
344
  selected: z.array(OptionIdSchema)
315
345
  });
346
+ const SetUrlPatchSchema = z.object({
347
+ op: z.literal("set_url"),
348
+ fieldId: IdSchema,
349
+ value: z.string().nullable()
350
+ });
351
+ const SetUrlListPatchSchema = z.object({
352
+ op: z.literal("set_url_list"),
353
+ fieldId: IdSchema,
354
+ items: z.array(z.string())
355
+ });
316
356
  const ClearFieldPatchSchema = z.object({
317
357
  op: z.literal("clear_field"),
318
358
  fieldId: IdSchema
319
359
  });
360
+ const SkipFieldPatchSchema = z.object({
361
+ op: z.literal("skip_field"),
362
+ fieldId: IdSchema,
363
+ reason: z.string().optional()
364
+ });
320
365
  const PatchSchema = z.discriminatedUnion("op", [
321
366
  SetStringPatchSchema,
322
367
  SetNumberPatchSchema,
@@ -324,7 +369,10 @@ const PatchSchema = z.discriminatedUnion("op", [
324
369
  SetCheckboxesPatchSchema,
325
370
  SetSingleSelectPatchSchema,
326
371
  SetMultiSelectPatchSchema,
327
- ClearFieldPatchSchema
372
+ SetUrlPatchSchema,
373
+ SetUrlListPatchSchema,
374
+ ClearFieldPatchSchema,
375
+ SkipFieldPatchSchema
328
376
  ]);
329
377
  const StepResultSchema = z.object({
330
378
  structureSummary: StructureSummarySchema,
@@ -343,14 +391,25 @@ const HarnessConfigSchema = z.object({
343
391
  targetRoles: z.array(z.string()).optional(),
344
392
  fillMode: FillModeSchema.optional()
345
393
  });
394
+ const SessionTurnStatsSchema = z.object({
395
+ inputTokens: z.number().int().nonnegative().optional(),
396
+ outputTokens: z.number().int().nonnegative().optional(),
397
+ toolCalls: z.array(z.object({
398
+ name: z.string(),
399
+ count: z.number().int().positive()
400
+ })).optional()
401
+ });
346
402
  const SessionTurnSchema = z.object({
347
403
  turn: z.number().int().positive(),
348
404
  inspect: z.object({ issues: z.array(InspectIssueSchema) }),
349
405
  apply: z.object({ patches: z.array(PatchSchema) }),
350
406
  after: z.object({
351
407
  requiredIssueCount: z.number().int().nonnegative(),
352
- markdownSha256: z.string()
353
- })
408
+ markdownSha256: z.string(),
409
+ answeredFieldCount: z.number().int().nonnegative(),
410
+ skippedFieldCount: z.number().int().nonnegative()
411
+ }),
412
+ llm: SessionTurnStatsSchema.optional()
354
413
  });
355
414
  const SessionFinalSchema = z.object({
356
415
  expectComplete: z.boolean(),
@@ -358,7 +417,7 @@ const SessionFinalSchema = z.object({
358
417
  });
359
418
  const SessionTranscriptSchema = z.object({
360
419
  sessionVersion: z.string(),
361
- mode: z.enum(["mock", "live"]),
420
+ mode: MockModeSchema,
362
421
  form: z.object({ path: z.string() }),
363
422
  validators: z.object({ code: z.string().optional() }).optional(),
364
423
  mock: z.object({ completedMock: z.string() }).optional(),
@@ -472,6 +531,35 @@ function formatSuggestedLlms() {
472
531
  }
473
532
  return lines.join("\n");
474
533
  }
534
+ /**
535
+ * Web search configuration per provider.
536
+ */
537
+ const WEB_SEARCH_CONFIG = {
538
+ openai: {
539
+ supported: true,
540
+ toolName: "web_search_preview",
541
+ exportName: "openaiTools"
542
+ },
543
+ google: {
544
+ supported: true,
545
+ toolName: "googleSearch",
546
+ exportName: "googleTools"
547
+ },
548
+ xai: {
549
+ supported: true,
550
+ toolName: "xai_search"
551
+ },
552
+ anthropic: { supported: false },
553
+ deepseek: { supported: false }
554
+ };
555
+ /**
556
+ * Get web search tool configuration for a provider.
557
+ * Returns undefined if provider doesn't support web search.
558
+ */
559
+ function getWebSearchConfig(provider) {
560
+ const config = WEB_SEARCH_CONFIG[provider];
561
+ return config?.supported ? config : void 0;
562
+ }
475
563
 
476
564
  //#endregion
477
565
  //#region src/engine/serialize.ts
@@ -647,6 +735,43 @@ function serializeCheckboxesField(field, value) {
647
735
  return `{% checkboxes ${serializeAttrs(attrs)} %}\n${serializeOptions(field.options, value?.values ?? {})}\n{% /checkboxes %}`;
648
736
  }
649
737
  /**
738
+ * Serialize a url-field.
739
+ */
740
+ function serializeUrlField(field, value) {
741
+ const attrs = {
742
+ id: field.id,
743
+ label: field.label
744
+ };
745
+ if (field.required) attrs.required = field.required;
746
+ if (field.priority !== DEFAULT_PRIORITY) attrs.priority = field.priority;
747
+ if (field.role !== AGENT_ROLE) attrs.role = field.role;
748
+ if (field.validate) attrs.validate = field.validate;
749
+ const attrStr = serializeAttrs(attrs);
750
+ let content = "";
751
+ if (value?.value) content = `\n\`\`\`value\n${value.value}\n\`\`\`\n`;
752
+ return `{% url-field ${attrStr} %}${content}{% /url-field %}`;
753
+ }
754
+ /**
755
+ * Serialize a url-list field.
756
+ */
757
+ function serializeUrlListField(field, value) {
758
+ const attrs = {
759
+ id: field.id,
760
+ label: field.label
761
+ };
762
+ if (field.required) attrs.required = field.required;
763
+ if (field.priority !== DEFAULT_PRIORITY) attrs.priority = field.priority;
764
+ if (field.role !== AGENT_ROLE) attrs.role = field.role;
765
+ if (field.minItems !== void 0) attrs.minItems = field.minItems;
766
+ if (field.maxItems !== void 0) attrs.maxItems = field.maxItems;
767
+ if (field.uniqueItems) attrs.uniqueItems = field.uniqueItems;
768
+ if (field.validate) attrs.validate = field.validate;
769
+ const attrStr = serializeAttrs(attrs);
770
+ let content = "";
771
+ if (value?.items && value.items.length > 0) content = `\n\`\`\`value\n${value.items.join("\n")}\n\`\`\`\n`;
772
+ return `{% url-list ${attrStr} %}${content}{% /url-list %}`;
773
+ }
774
+ /**
650
775
  * Serialize a field to Markdoc format.
651
776
  */
652
777
  function serializeField(field, values) {
@@ -658,6 +783,8 @@ function serializeField(field, values) {
658
783
  case "single_select": return serializeSingleSelectField(field, value);
659
784
  case "multi_select": return serializeMultiSelectField(field, value);
660
785
  case "checkboxes": return serializeCheckboxesField(field, value);
786
+ case "url": return serializeUrlField(field, value);
787
+ case "url_list": return serializeUrlListField(field, value);
661
788
  }
662
789
  }
663
790
  /**
@@ -794,6 +921,18 @@ function serializeFieldRaw(field, values) {
794
921
  }
795
922
  break;
796
923
  }
924
+ case "url": {
925
+ const urlValue = value;
926
+ if (urlValue?.value) lines.push(urlValue.value);
927
+ else lines.push("_(empty)_");
928
+ break;
929
+ }
930
+ case "url_list": {
931
+ const urlListValue = value;
932
+ if (urlListValue?.items && urlListValue.items.length > 0) for (const item of urlListValue.items) lines.push(`- ${item}`);
933
+ else lines.push("_(empty)_");
934
+ break;
935
+ }
797
936
  }
798
937
  return lines.join("\n");
799
938
  }
@@ -861,7 +1000,9 @@ function computeStructureSummary(schema) {
861
1000
  string_list: 0,
862
1001
  checkboxes: 0,
863
1002
  single_select: 0,
864
- multi_select: 0
1003
+ multi_select: 0,
1004
+ url: 0,
1005
+ url_list: 0
865
1006
  };
866
1007
  const groupsById = {};
867
1008
  const fieldsById = {};
@@ -922,6 +1063,11 @@ function isFieldSubmitted(field, value) {
922
1063
  }
923
1064
  return false;
924
1065
  }
1066
+ case "url": {
1067
+ const v = value;
1068
+ return v.value !== null && v.value.trim() !== "";
1069
+ }
1070
+ case "url_list": return value.items.length > 0;
925
1071
  }
926
1072
  }
927
1073
  /**
@@ -980,18 +1126,21 @@ function computeFieldState(field, value, issueCount) {
980
1126
  /**
981
1127
  * Compute progress for a single field.
982
1128
  */
983
- function computeFieldProgress(field, value, issues) {
1129
+ function computeFieldProgress(field, value, issues, skipInfo) {
984
1130
  const issueCount = issues.filter((i) => i.ref === field.id).length;
985
1131
  const submitted = isFieldSubmitted(field, value);
986
1132
  const valid = issueCount === 0;
987
1133
  const state = computeFieldState(field, value, issueCount);
1134
+ const skipped = skipInfo?.skipped ?? false;
988
1135
  const progress = {
989
1136
  kind: field.kind,
990
1137
  required: field.required,
991
1138
  submitted,
992
1139
  state,
993
1140
  valid,
994
- issueCount
1141
+ issueCount,
1142
+ skipped,
1143
+ skipReason: skipInfo?.reason
995
1144
  };
996
1145
  if (field.kind === "checkboxes") progress.checkboxProgress = computeCheckboxProgress(field, value);
997
1146
  return progress;
@@ -1002,9 +1151,10 @@ function computeFieldProgress(field, value, issues) {
1002
1151
  * @param schema - The form schema
1003
1152
  * @param values - Current field values
1004
1153
  * @param issues - Validation issues (from inspect)
1154
+ * @param skips - Skip state per field (from skip_field patches)
1005
1155
  * @returns Progress summary with field states and counts
1006
1156
  */
1007
- function computeProgressSummary(schema, values, issues) {
1157
+ function computeProgressSummary(schema, values, issues, skips = {}) {
1008
1158
  const fields = {};
1009
1159
  const counts = {
1010
1160
  totalFields: 0,
@@ -1014,15 +1164,22 @@ function computeProgressSummary(schema, values, issues) {
1014
1164
  incompleteFields: 0,
1015
1165
  invalidFields: 0,
1016
1166
  emptyRequiredFields: 0,
1017
- emptyOptionalFields: 0
1167
+ emptyOptionalFields: 0,
1168
+ answeredFields: 0,
1169
+ skippedFields: 0
1018
1170
  };
1019
1171
  for (const group of schema.groups) for (const field of group.children) {
1020
1172
  const value = values[field.id];
1021
- const progress = computeFieldProgress(field, value, issues);
1173
+ const skipInfo = skips[field.id];
1174
+ const progress = computeFieldProgress(field, value, issues, skipInfo);
1022
1175
  fields[field.id] = progress;
1023
1176
  counts.totalFields++;
1024
1177
  if (progress.required) counts.requiredFields++;
1025
- if (progress.submitted) counts.submittedFields++;
1178
+ if (progress.submitted) {
1179
+ counts.submittedFields++;
1180
+ counts.answeredFields++;
1181
+ }
1182
+ if (progress.skipped) counts.skippedFields++;
1026
1183
  if (progress.state === "complete") counts.completeFields++;
1027
1184
  if (progress.state === "incomplete") counts.incompleteFields++;
1028
1185
  if (progress.state === "invalid") counts.invalidFields++;
@@ -1050,11 +1207,23 @@ function computeFormState(progress) {
1050
1207
  /**
1051
1208
  * Determine if the form is complete (ready for submission).
1052
1209
  *
1210
+ * A form is complete when:
1211
+ * 1. No required fields are empty
1212
+ * 2. No fields have validation errors
1213
+ * 3. No fields are in incomplete state (e.g., partial checkbox completion)
1214
+ * 4. All fields must be addressed (answered + skipped == total)
1215
+ *
1216
+ * Every field must be explicitly addressed - either filled with a value or
1217
+ * skipped with a reason. This ensures agents fully process all fields.
1218
+ *
1053
1219
  * @param progress - The progress summary
1054
1220
  * @returns True if the form is complete
1055
1221
  */
1056
1222
  function isFormComplete(progress) {
1057
- return progress.counts.invalidFields === 0 && progress.counts.incompleteFields === 0 && progress.counts.emptyRequiredFields === 0;
1223
+ const { counts } = progress;
1224
+ const baseComplete = counts.invalidFields === 0 && counts.incompleteFields === 0 && counts.emptyRequiredFields === 0;
1225
+ const allFieldsAccountedFor = counts.answeredFields + counts.skippedFields === counts.totalFields;
1226
+ return baseComplete && allFieldsAccountedFor;
1058
1227
  }
1059
1228
  /**
1060
1229
  * Compute all summaries for a parsed form.
@@ -1062,11 +1231,12 @@ function isFormComplete(progress) {
1062
1231
  * @param schema - The form schema
1063
1232
  * @param values - Current field values
1064
1233
  * @param issues - Validation issues
1234
+ * @param skips - Skip state per field (from skip_field patches)
1065
1235
  * @returns All computed summaries
1066
1236
  */
1067
- function computeAllSummaries(schema, values, issues) {
1237
+ function computeAllSummaries(schema, values, issues, skips = {}) {
1068
1238
  const structureSummary = computeStructureSummary(schema);
1069
- const progressSummary = computeProgressSummary(schema, values, issues);
1239
+ const progressSummary = computeProgressSummary(schema, values, issues, skips);
1070
1240
  return {
1071
1241
  structureSummary,
1072
1242
  progressSummary,
@@ -1332,6 +1502,96 @@ function validateCheckboxesField(field, value) {
1332
1502
  return issues;
1333
1503
  }
1334
1504
  /**
1505
+ * Check if a string is a valid URL.
1506
+ * Uses URL constructor for validation (RFC 3986 compliant).
1507
+ */
1508
+ function isValidUrl(str) {
1509
+ try {
1510
+ const url = new URL(str);
1511
+ return url.protocol === "http:" || url.protocol === "https:";
1512
+ } catch {
1513
+ return false;
1514
+ }
1515
+ }
1516
+ /**
1517
+ * Validate a URL field.
1518
+ */
1519
+ function validateUrlField(field, value) {
1520
+ const issues = [];
1521
+ const urlValue = value?.value ?? null;
1522
+ if (field.required && (urlValue === null || urlValue.trim() === "")) {
1523
+ issues.push({
1524
+ severity: "error",
1525
+ message: `Required field "${field.label}" is empty`,
1526
+ ref: field.id,
1527
+ source: "builtin"
1528
+ });
1529
+ return issues;
1530
+ }
1531
+ if (urlValue === null || urlValue === "") return issues;
1532
+ if (!isValidUrl(urlValue)) issues.push({
1533
+ severity: "error",
1534
+ message: `"${field.label}" is not a valid URL`,
1535
+ ref: field.id,
1536
+ source: "builtin"
1537
+ });
1538
+ return issues;
1539
+ }
1540
+ /**
1541
+ * Validate a URL list field.
1542
+ */
1543
+ function validateUrlListField(field, value) {
1544
+ const issues = [];
1545
+ const items = value?.items ?? [];
1546
+ if (field.required && items.length === 0) {
1547
+ issues.push({
1548
+ severity: "error",
1549
+ message: `Required field "${field.label}" is empty`,
1550
+ ref: field.id,
1551
+ source: "builtin"
1552
+ });
1553
+ return issues;
1554
+ }
1555
+ if (items.length === 0) return issues;
1556
+ if (field.minItems !== void 0 && items.length < field.minItems) issues.push({
1557
+ severity: "error",
1558
+ message: `"${field.label}" must have at least ${field.minItems} items (got ${items.length})`,
1559
+ ref: field.id,
1560
+ source: "builtin"
1561
+ });
1562
+ if (field.maxItems !== void 0 && items.length > field.maxItems) issues.push({
1563
+ severity: "error",
1564
+ message: `"${field.label}" must have at most ${field.maxItems} items (got ${items.length})`,
1565
+ ref: field.id,
1566
+ source: "builtin"
1567
+ });
1568
+ for (let i = 0; i < items.length; i++) {
1569
+ const item = items[i];
1570
+ if (item !== void 0 && !isValidUrl(item)) issues.push({
1571
+ severity: "error",
1572
+ message: `Item ${i + 1} in "${field.label}" is not a valid URL`,
1573
+ ref: field.id,
1574
+ source: "builtin"
1575
+ });
1576
+ }
1577
+ if (field.uniqueItems) {
1578
+ const seen = /* @__PURE__ */ new Set();
1579
+ for (const item of items) {
1580
+ if (seen.has(item)) {
1581
+ issues.push({
1582
+ severity: "error",
1583
+ message: `Duplicate URL "${item}" in "${field.label}"`,
1584
+ ref: field.id,
1585
+ source: "builtin"
1586
+ });
1587
+ break;
1588
+ }
1589
+ seen.add(item);
1590
+ }
1591
+ }
1592
+ return issues;
1593
+ }
1594
+ /**
1335
1595
  * Validate a single field.
1336
1596
  */
1337
1597
  function validateField(field, values) {
@@ -1343,6 +1603,8 @@ function validateField(field, values) {
1343
1603
  case "single_select": return validateSingleSelectField(field, value);
1344
1604
  case "multi_select": return validateMultiSelectField(field, value);
1345
1605
  case "checkboxes": return validateCheckboxesField(field, value);
1606
+ case "url": return validateUrlField(field, value);
1607
+ case "url_list": return validateUrlListField(field, value);
1346
1608
  }
1347
1609
  }
1348
1610
  /**
@@ -1485,14 +1747,14 @@ function validate(form, opts) {
1485
1747
  function inspect(form, options = {}) {
1486
1748
  const validationInspectIssues = convertValidationIssues(validate(form, { skipCodeValidators: options.skipCodeValidators }).issues, form);
1487
1749
  const structureSummary = computeStructureSummary(form.schema);
1488
- const progressSummary = computeProgressSummary(form.schema, form.valuesByFieldId, validationInspectIssues);
1750
+ const progressSummary = computeProgressSummary(form.schema, form.valuesByFieldId, validationInspectIssues, form.skipsByFieldId);
1489
1751
  const formState = computeFormState(progressSummary);
1490
- const filteredIssues = filterIssuesByRole(sortAndAssignPriorities(addOptionalEmptyIssues(validationInspectIssues, form, progressSummary.fields), form), form, options.targetRoles);
1752
+ const issues = filterIssuesByRole(sortAndAssignPriorities(addOptionalEmptyIssues(validationInspectIssues, form, progressSummary.fields), form), form, options.targetRoles);
1491
1753
  return {
1492
1754
  structureSummary,
1493
1755
  progressSummary,
1494
- issues: filteredIssues,
1495
- isComplete: !filteredIssues.some((i) => i.severity === "required"),
1756
+ issues,
1757
+ isComplete: issues.length === 0,
1496
1758
  formState
1497
1759
  };
1498
1760
  }
@@ -1511,18 +1773,22 @@ function convertValidationIssues(validationIssues, form) {
1511
1773
  }
1512
1774
  /**
1513
1775
  * Add issues for empty optional fields that don't already have issues.
1776
+ * Fields that have been explicitly skipped do not get optional_empty issues.
1514
1777
  */
1515
1778
  function addOptionalEmptyIssues(existingIssues, form, fieldProgress) {
1516
1779
  const issues = [...existingIssues];
1517
1780
  const fieldsWithIssues = new Set(existingIssues.map((i) => i.ref));
1518
- for (const [fieldId, progress] of Object.entries(fieldProgress)) if (progress.state === "empty" && !fieldsWithIssues.has(fieldId) && !isRequiredField(fieldId, form)) issues.push({
1519
- ref: fieldId,
1520
- scope: "field",
1521
- reason: "optional_empty",
1522
- message: "Optional field has no value",
1523
- severity: "recommended",
1524
- priority: 0
1525
- });
1781
+ for (const [fieldId, progress] of Object.entries(fieldProgress)) {
1782
+ if (progress.skipped) continue;
1783
+ if (progress.state === "empty" && !fieldsWithIssues.has(fieldId) && !isRequiredField(fieldId, form)) issues.push({
1784
+ ref: fieldId,
1785
+ scope: "field",
1786
+ reason: "optional_empty",
1787
+ message: "Optional field has no value",
1788
+ severity: "recommended",
1789
+ priority: 0
1790
+ });
1791
+ }
1526
1792
  return issues;
1527
1793
  }
1528
1794
  /**
@@ -1812,7 +2078,25 @@ function validatePatch(form, patch, index) {
1812
2078
  };
1813
2079
  break;
1814
2080
  }
2081
+ case "set_url":
2082
+ if (field.kind !== "url") return {
2083
+ patchIndex: index,
2084
+ message: `Cannot apply set_url to ${field.kind} field "${field.id}"`
2085
+ };
2086
+ break;
2087
+ case "set_url_list":
2088
+ if (field.kind !== "url_list") return {
2089
+ patchIndex: index,
2090
+ message: `Cannot apply set_url_list to ${field.kind} field "${field.id}"`
2091
+ };
2092
+ break;
1815
2093
  case "clear_field": break;
2094
+ case "skip_field":
2095
+ if (field.required) return {
2096
+ patchIndex: index,
2097
+ message: `Cannot skip required field "${field.id}"`
2098
+ };
2099
+ break;
1816
2100
  }
1817
2101
  return null;
1818
2102
  }
@@ -1889,6 +2173,24 @@ function applySetCheckboxes(values, patch) {
1889
2173
  };
1890
2174
  }
1891
2175
  /**
2176
+ * Apply a set_url patch.
2177
+ */
2178
+ function applySetUrl(values, patch) {
2179
+ values[patch.fieldId] = {
2180
+ kind: "url",
2181
+ value: patch.value
2182
+ };
2183
+ }
2184
+ /**
2185
+ * Apply a set_url_list patch.
2186
+ */
2187
+ function applySetUrlList(values, patch) {
2188
+ values[patch.fieldId] = {
2189
+ kind: "url_list",
2190
+ items: patch.items
2191
+ };
2192
+ }
2193
+ /**
1892
2194
  * Apply a clear_field patch.
1893
2195
  */
1894
2196
  function applyClearField(form, values, patch) {
@@ -1931,33 +2233,73 @@ function applyClearField(form, values, patch) {
1931
2233
  values: {}
1932
2234
  };
1933
2235
  break;
2236
+ case "url":
2237
+ values[patch.fieldId] = {
2238
+ kind: "url",
2239
+ value: null
2240
+ };
2241
+ break;
2242
+ case "url_list":
2243
+ values[patch.fieldId] = {
2244
+ kind: "url_list",
2245
+ items: []
2246
+ };
2247
+ break;
1934
2248
  }
1935
2249
  }
1936
2250
  /**
1937
- * Apply a single patch to the values.
2251
+ * Apply a skip_field patch.
2252
+ * Marks the field as skipped and clears any existing value.
1938
2253
  */
1939
- function applyPatch(form, values, patch) {
2254
+ function applySkipField(form, values, skips, patch) {
2255
+ if (!findField(form, patch.fieldId)) return;
2256
+ skips[patch.fieldId] = {
2257
+ skipped: true,
2258
+ reason: patch.reason
2259
+ };
2260
+ delete values[patch.fieldId];
2261
+ }
2262
+ /**
2263
+ * Apply a single patch to the values and skips.
2264
+ */
2265
+ function applyPatch(form, values, skips, patch) {
1940
2266
  switch (patch.op) {
1941
2267
  case "set_string":
1942
2268
  applySetString(values, patch);
2269
+ delete skips[patch.fieldId];
1943
2270
  break;
1944
2271
  case "set_number":
1945
2272
  applySetNumber(values, patch);
2273
+ delete skips[patch.fieldId];
1946
2274
  break;
1947
2275
  case "set_string_list":
1948
2276
  applySetStringList(values, patch);
2277
+ delete skips[patch.fieldId];
1949
2278
  break;
1950
2279
  case "set_single_select":
1951
2280
  applySetSingleSelect(values, patch);
2281
+ delete skips[patch.fieldId];
1952
2282
  break;
1953
2283
  case "set_multi_select":
1954
2284
  applySetMultiSelect(values, patch);
2285
+ delete skips[patch.fieldId];
1955
2286
  break;
1956
2287
  case "set_checkboxes":
1957
2288
  applySetCheckboxes(values, patch);
2289
+ delete skips[patch.fieldId];
2290
+ break;
2291
+ case "set_url":
2292
+ applySetUrl(values, patch);
2293
+ break;
2294
+ case "set_url_list":
2295
+ applySetUrlList(values, patch);
1958
2296
  break;
1959
2297
  case "clear_field":
1960
2298
  applyClearField(form, values, patch);
2299
+ delete skips[patch.fieldId];
2300
+ break;
2301
+ case "skip_field":
2302
+ applySkipField(form, values, skips, patch);
1961
2303
  break;
1962
2304
  }
1963
2305
  }
@@ -1989,7 +2331,7 @@ function convertToInspectIssues(form) {
1989
2331
  */
1990
2332
  function applyPatches(form, patches) {
1991
2333
  if (validatePatches(form, patches).length > 0) {
1992
- const summaries$1 = computeAllSummaries(form.schema, form.valuesByFieldId, []);
2334
+ const summaries$1 = computeAllSummaries(form.schema, form.valuesByFieldId, [], form.skipsByFieldId);
1993
2335
  const issues$1 = convertToInspectIssues(form);
1994
2336
  return {
1995
2337
  applyStatus: "rejected",
@@ -2001,10 +2343,12 @@ function applyPatches(form, patches) {
2001
2343
  };
2002
2344
  }
2003
2345
  const newValues = { ...form.valuesByFieldId };
2004
- for (const patch of patches) applyPatch(form, newValues, patch);
2346
+ const newSkips = { ...form.skipsByFieldId };
2347
+ for (const patch of patches) applyPatch(form, newValues, newSkips, patch);
2005
2348
  form.valuesByFieldId = newValues;
2349
+ form.skipsByFieldId = newSkips;
2006
2350
  const issues = convertToInspectIssues(form);
2007
- const summaries = computeAllSummaries(form.schema, newValues, issues);
2351
+ const summaries = computeAllSummaries(form.schema, newValues, issues, newSkips);
2008
2352
  return {
2009
2353
  applyStatus: "applied",
2010
2354
  structureSummary: summaries.structureSummary,
@@ -2016,5 +2360,4 @@ function applyPatches(form, patches) {
2016
2360
  }
2017
2361
 
2018
2362
  //#endregion
2019
- export { PatchSchema as $, DocumentationBlockSchema as A, IdSchema as B, ApplyResultSchema as C, StructureSummarySchema as Ct, CheckboxesFieldSchema as D, CheckboxValueSchema as E, FieldProgressSchema as F, MarkformFrontmatterSchema as G, InspectResultSchema as H, FieldSchema as I, MultiSelectValueSchema as J, MultiCheckboxStateSchema as K, FieldValueSchema as L, ExplicitCheckboxValueSchema as M, FieldGroupSchema as N, CheckboxesValueSchema as O, FieldKindSchema as P, OptionSchema as Q, FormSchemaSchema as R, parseRolesFlag as S, StringValueSchema as St, CheckboxProgressCountsSchema as T, ValidatorRefSchema as Tt, IssueReasonSchema as U, InspectIssueSchema as V, IssueScopeSchema as W, NumberValueSchema as X, NumberFieldSchema as Y, OptionIdSchema as Z, DEFAULT_PRIORITY as _, SourceRangeSchema as _t, computeAllSummaries as a, SessionTurnSchema as at, USER_ROLE as b, StringListFieldSchema as bt, computeStructureSummary as c, SetNumberPatchSchema as ct, serializeRawMarkdown as d, SetStringPatchSchema as dt, ProgressCountsSchema as et, AGENT_ROLE as f, SeveritySchema as ft, DEFAULT_PORT as g, SourcePositionSchema as gt, DEFAULT_MAX_TURNS as h, SingleSelectValueSchema as ht, validate as i, SessionTranscriptSchema as it, DocumentationTagSchema as j, ClearFieldPatchSchema as k, isFormComplete as l, SetSingleSelectPatchSchema as lt, DEFAULT_MAX_PATCHES_PER_TURN as m, SingleSelectFieldSchema as mt, getFieldsForRoles as n, ProgressSummarySchema as nt, computeFormState as o, SetCheckboxesPatchSchema as ot, DEFAULT_MAX_ISSUES as p, SimpleCheckboxStateSchema as pt, MultiSelectFieldSchema as q, inspect as r, SessionFinalSchema as rt, computeProgressSummary as s, SetMultiSelectPatchSchema as st, applyPatches as t, ProgressStateSchema as tt, serialize as u, SetStringListPatchSchema as ut, DEFAULT_ROLE_INSTRUCTIONS as v, StepResultSchema as vt, CheckboxModeSchema as w, ValidationIssueSchema as wt, formatSuggestedLlms as x, StringListValueSchema as xt, SUGGESTED_LLMS as y, StringFieldSchema as yt, HarnessConfigSchema as z };
2020
- //# sourceMappingURL=apply-C0vjijlP.mjs.map
2363
+ export { OptionSchema as $, ClearFieldPatchSchema as A, HarnessConfigSchema as B, parseRolesFlag as C, StringValueSchema as Ct, CheckboxValueSchema as D, CheckboxProgressCountsSchema as E, ValidatorRefSchema as Et, FieldKindSchema as F, IssueScopeSchema as G, InspectIssueSchema as H, FieldProgressSchema as I, MultiSelectFieldSchema as J, MarkformFrontmatterSchema as K, FieldSchema as L, DocumentationTagSchema as M, ExplicitCheckboxValueSchema as N, CheckboxesFieldSchema as O, FieldGroupSchema as P, OptionIdSchema as Q, FieldValueSchema as R, getWebSearchConfig as S, StringListValueSchema as St, CheckboxModeSchema as T, ValidationIssueSchema as Tt, InspectResultSchema as U, IdSchema as V, IssueReasonSchema as W, NumberFieldSchema as X, MultiSelectValueSchema as Y, NumberValueSchema as Z, DEFAULT_PRIORITY as _, SourcePositionSchema as _t, computeAllSummaries as a, SessionTranscriptSchema as at, USER_ROLE as b, StringFieldSchema as bt, computeStructureSummary as c, SetMultiSelectPatchSchema as ct, serializeRawMarkdown as d, SetStringListPatchSchema as dt, PatchSchema as et, AGENT_ROLE as f, SetStringPatchSchema as ft, DEFAULT_PORT as g, SingleSelectValueSchema as gt, DEFAULT_MAX_TURNS as h, SingleSelectFieldSchema as ht, validate as i, SessionFinalSchema as it, DocumentationBlockSchema as j, CheckboxesValueSchema as k, isFormComplete as l, SetNumberPatchSchema as lt, DEFAULT_MAX_PATCHES_PER_TURN as m, SimpleCheckboxStateSchema as mt, getFieldsForRoles as n, ProgressStateSchema as nt, computeFormState as o, SessionTurnSchema as ot, DEFAULT_MAX_ISSUES as p, SeveritySchema as pt, MultiCheckboxStateSchema as q, inspect as r, ProgressSummarySchema as rt, computeProgressSummary as s, SetCheckboxesPatchSchema as st, applyPatches as t, ProgressCountsSchema as tt, serialize as u, SetSingleSelectPatchSchema as ut, DEFAULT_ROLE_INSTRUCTIONS as v, SourceRangeSchema as vt, ApplyResultSchema as w, StructureSummarySchema as wt, formatSuggestedLlms as x, StringListFieldSchema as xt, SUGGESTED_LLMS as y, StepResultSchema as yt, FormSchemaSchema as z };