markform 0.1.8 → 0.1.9

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.
@@ -1,6 +1,6 @@
1
1
 
2
- import { L as PatchSchema, V as RunModeSchema } from "./coreTypes-DJtu8OOp.mjs";
3
- import { C as DEFAULT_ROLES, I as getWebSearchConfig, S as DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN, _ as DEFAULT_MAX_PATCHES_PER_TURN, b as DEFAULT_PRIORITY, d as serialize, g as DEFAULT_MAX_ISSUES_PER_TURN, i as inspect, m as AGENT_ROLE, r as getFieldsForRoles, t as applyPatches, v as DEFAULT_MAX_TURNS, w as DEFAULT_ROLE_INSTRUCTIONS, x as DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN } from "./apply-BUU2QcJ2.mjs";
2
+ import { L as PatchSchema, V as RunModeSchema } from "./coreTypes-B1oI7qvV.mjs";
3
+ import { C as DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN, L as getWebSearchConfig, S as DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN, T as DEFAULT_ROLE_INSTRUCTIONS, _ as DEFAULT_MAX_ISSUES_PER_TURN, d as serialize, i as inspect, m as AGENT_ROLE, r as getFieldsForRoles, t as applyPatches, v as DEFAULT_MAX_PATCHES_PER_TURN, w as DEFAULT_ROLES, x as DEFAULT_PRIORITY, y as DEFAULT_MAX_TURNS } from "./apply-B2kt6C2z.mjs";
4
4
  import { z } from "zod";
5
5
  import Markdoc from "@markdoc/markdoc";
6
6
  import YAML from "yaml";
@@ -528,6 +528,10 @@ function isValueEmpty(value) {
528
528
  case "multi_select": return value.selected.length === 0;
529
529
  case "checkboxes": return Object.values(value.values).every((v) => v === "todo" || v === "unfilled");
530
530
  case "table": return value.rows.length === 0;
531
+ default: {
532
+ const _exhaustive = value;
533
+ throw new Error(`Unhandled field value kind: ${_exhaustive.kind}`);
534
+ }
531
535
  }
532
536
  }
533
537
  /**
@@ -1751,6 +1755,10 @@ function fieldToJsonSchema(field, docs, options, groupId) {
1751
1755
  case "multi_select": return multiSelectFieldToJsonSchema(field, docs, opts, groupId);
1752
1756
  case "checkboxes": return checkboxesFieldToJsonSchema(field, docs, opts, groupId);
1753
1757
  case "table": return tableFieldToJsonSchema(field, docs, opts, groupId);
1758
+ default: {
1759
+ const _exhaustive = field;
1760
+ throw new Error(`Unhandled field kind: ${_exhaustive.kind}`);
1761
+ }
1754
1762
  }
1755
1763
  }
1756
1764
  /**
@@ -2387,6 +2395,10 @@ function coerceToFieldPatch(form, fieldId, rawValue) {
2387
2395
  case "date": return coerceToDate(fieldId, rawValue);
2388
2396
  case "year": return coerceToYear(fieldId, rawValue);
2389
2397
  case "table": return coerceToTable(fieldId, rawValue);
2398
+ default: {
2399
+ const _exhaustive = field;
2400
+ throw new Error(`Unhandled field kind: ${_exhaustive.kind}`);
2401
+ }
2390
2402
  }
2391
2403
  }
2392
2404
  /**
@@ -2523,9 +2535,10 @@ var FormHarness = class {
2523
2535
  * @param issues - Issues that were shown to the agent (for recording)
2524
2536
  * @param llmStats - Optional LLM stats for session logging
2525
2537
  * @param context - Optional context prompts sent to LLM (for session logging)
2538
+ * @param wire - Optional wire format for comprehensive session logging
2526
2539
  * @returns StepResult after applying patches
2527
2540
  */
2528
- apply(patches, issues, llmStats, context) {
2541
+ apply(patches, issues, llmStats, context, wire) {
2529
2542
  if (this.state !== "wait") throw new Error(`Cannot apply in state: ${this.state}`);
2530
2543
  if (patches.length > this.config.maxPatchesPerTurn) throw new Error(`Too many patches: ${patches.length} > ${this.config.maxPatchesPerTurn}`);
2531
2544
  const applyResult = applyPatches(this.form, patches);
@@ -2534,7 +2547,7 @@ var FormHarness = class {
2534
2547
  const stepResult = this.computeStepResult(result);
2535
2548
  stepResult.patchesApplied = patchesActuallyApplied;
2536
2549
  stepResult.rejectedPatches = applyResult.rejectedPatches;
2537
- this.recordTurn(issues, patches, result, llmStats, context, applyResult.rejectedPatches);
2550
+ this.recordTurn(issues, patches, result, llmStats, context, applyResult.rejectedPatches, wire);
2538
2551
  if (stepResult.issues.length === 0 || this.turnNumber >= this.config.maxTurns) this.state = "complete";
2539
2552
  else this.state = "wait";
2540
2553
  return stepResult;
@@ -2558,7 +2571,7 @@ var FormHarness = class {
2558
2571
  /**
2559
2572
  * Record a turn in the session transcript.
2560
2573
  */
2561
- recordTurn(issues, patches, result, llmStats, context, rejectedPatches) {
2574
+ recordTurn(issues, patches, result, llmStats, context, rejectedPatches, wire) {
2562
2575
  const hash = sha256(serialize(this.form));
2563
2576
  const requiredIssueCount = result.issues.filter((i) => i.severity === "required").length;
2564
2577
  const turn = {
@@ -2577,6 +2590,7 @@ var FormHarness = class {
2577
2590
  };
2578
2591
  if (context) turn.context = context;
2579
2592
  if (llmStats) turn.llm = llmStats;
2593
+ if (wire) turn.wire = wire;
2580
2594
  this.turns.push(turn);
2581
2595
  }
2582
2596
  /**
@@ -2696,14 +2710,14 @@ var MockAgent = class {
2696
2710
  for (const group of completedForm.schema.groups) for (const field of group.children) this.fieldMap.set(field.id, field);
2697
2711
  }
2698
2712
  /**
2699
- * Generate patches from the completed mock to address issues.
2713
+ * Invoke the fill_form tool using the completed mock to address issues.
2700
2714
  *
2701
2715
  * Processes issues in priority order, generating patches for
2702
2716
  * fields that have values in the completed mock. For fields with no
2703
2717
  * value (empty optional fields), generates skip_field patches.
2704
2718
  * Returns AgentResponse with patches but no stats (mock doesn't track LLM usage).
2705
2719
  */
2706
- async generatePatches(issues, _form, maxPatches) {
2720
+ async fillFormTool(issues, _form, maxPatches) {
2707
2721
  const patches = [];
2708
2722
  const addressedFields = /* @__PURE__ */ new Set();
2709
2723
  for (const issue of issues) {
@@ -2750,7 +2764,10 @@ var MockAgent = class {
2750
2764
  case "date": return value.value !== null;
2751
2765
  case "year": return value.value !== null;
2752
2766
  case "table": return value.rows.length > 0;
2753
- default: return false;
2767
+ default: {
2768
+ const _exhaustive = value;
2769
+ throw new Error(`Unhandled field value kind: ${_exhaustive.kind}`);
2770
+ }
2754
2771
  }
2755
2772
  }
2756
2773
  /**
@@ -2817,7 +2834,10 @@ var MockAgent = class {
2817
2834
  return patchRow;
2818
2835
  })
2819
2836
  };
2820
- default: return null;
2837
+ default: {
2838
+ const _exhaustive = field;
2839
+ throw new Error(`Unhandled field kind: ${_exhaustive.kind}`);
2840
+ }
2821
2841
  }
2822
2842
  }
2823
2843
  };
@@ -7855,11 +7875,14 @@ Guidelines:
7855
7875
  6. For number fields: use appropriate numeric values from verified sources
7856
7876
  7. For single_select: choose one valid option ID
7857
7877
  8. For multi_select: choose one or more valid option IDs
7858
- 9. For checkboxes: set appropriate states (done/todo for simple, yes/no for explicit)
7878
+ 9. For checkboxes: use the appropriate state for the checkbox mode:
7879
+ - Mode "simple": done (checked) or todo (unchecked)
7880
+ - Mode "multi": done, todo, or na (not applicable)
7881
+ - Mode "explicit": yes or no (must explicitly answer)
7859
7882
 
7860
7883
  CRITICAL: Accuracy is more important than completeness. Use skip_field when information cannot be verified.
7861
7884
 
7862
- Always use the generatePatches tool to submit your field values.
7885
+ Always use the fill_form tool to submit your field values.
7863
7886
  `;
7864
7887
  /**
7865
7888
  * Web search instructions appended when web search tools are available.
@@ -7878,21 +7901,15 @@ Guidelines:
7878
7901
  5. NEVER fill fields with guessed or assumed information
7879
7902
  `;
7880
7903
  /**
7881
- * Description for the generatePatches tool.
7882
- *
7883
- * This tells the model how to use the patch submission tool.
7884
- */
7885
- const GENERATE_PATCHES_TOOL_DESCRIPTION = "Generate patches to fill form fields. Each patch sets a field value. Use the field IDs from the issues list. Return patches for all issues you can address.";
7886
- /**
7887
7904
  * Header for the issues section in the context prompt.
7888
7905
  */
7889
7906
  const ISSUES_HEADER = "# Current Form Issues";
7890
7907
  /**
7891
7908
  * Template for the issues intro text.
7892
- * @param maxPatches - Maximum number of patches to generate
7909
+ * @param issueCount - Actual number of issues shown
7893
7910
  */
7894
- function getIssuesIntro(maxPatches) {
7895
- return `You need to address up to ${maxPatches} issues. Here are the current issues:`;
7911
+ function getIssuesIntro(issueCount) {
7912
+ return `You need to address ${issueCount} issue${issueCount === 1 ? "" : "s"}. Here are the current issues:`;
7896
7913
  }
7897
7914
  /**
7898
7915
  * Patch format examples by field kind.
@@ -7939,7 +7956,7 @@ function getPatchFormatHint(fieldKind, fieldId, columnIds) {
7939
7956
  */
7940
7957
  const PATCH_FORMAT_INSTRUCTIONS = `# Instructions
7941
7958
 
7942
- Use the generatePatches tool to submit patches for the fields above.
7959
+ Use the fill_form tool to submit patches for the fields above.
7943
7960
  Each patch should match the field kind:
7944
7961
  ${Object.entries(PATCH_FORMATS).map(([kind, format]) => `- ${kind}: ${format}`).join("\n")}
7945
7962
 
@@ -7948,6 +7965,16 @@ For table fields, use the column IDs shown in the field schema. Each row is an o
7948
7965
  If you cannot find verifiable information for a field, skip it:
7949
7966
  - skip: { op: "skip_field", fieldId: "...", reason: "Information not available" }`;
7950
7967
  /**
7968
+ * Simplified general instructions for use with inline field instructions.
7969
+ *
7970
+ * When inline field instructions are shown after each issue, we only need
7971
+ * general guidance about using the fill_form tool.
7972
+ */
7973
+ const GENERAL_INSTRUCTIONS = `# General Instructions
7974
+
7975
+ Use the fill_form tool to submit patches for the fields above.
7976
+ For table fields, each row is an object with column ID keys.`;
7977
+ /**
7951
7978
  * Section headers used when building the composed system prompt.
7952
7979
  */
7953
7980
  const SECTION_HEADERS = {
@@ -7958,6 +7985,19 @@ const SECTION_HEADERS = {
7958
7985
  additionalContext: "# Additional Context"
7959
7986
  };
7960
7987
 
7988
+ //#endregion
7989
+ //#region src/harness/toolApi.ts
7990
+ /**
7991
+ * Tool API Definitions
7992
+ *
7993
+ * Single source of truth for all LLM tool names, descriptions, and schemas.
7994
+ * This file defines the contract between markform and LLM agents.
7995
+ */
7996
+ /** The primary tool for filling form fields */
7997
+ const FILL_FORM_TOOL_NAME = "fill_form";
7998
+ /** Description shown to LLMs for the fill_form tool */
7999
+ const FILL_FORM_TOOL_DESCRIPTION = "Fill form fields by submitting patches. Each patch sets a value for one field. Use the field IDs from the issues list. Return patches for all issues you can address.";
8000
+
7961
8001
  //#endregion
7962
8002
  //#region src/harness/liveAgent.ts
7963
8003
  /**
@@ -7989,13 +8029,13 @@ var LiveAgent = class {
7989
8029
  * Useful for logging what capabilities the agent has.
7990
8030
  */
7991
8031
  getAvailableToolNames() {
7992
- const tools = ["generatePatches"];
8032
+ const tools = [FILL_FORM_TOOL_NAME];
7993
8033
  if (this.webSearchTools) tools.push(...Object.keys(this.webSearchTools));
7994
8034
  tools.push(...Object.keys(this.additionalTools));
7995
8035
  return [...new Set(tools)];
7996
8036
  }
7997
8037
  /**
7998
- * Generate patches using the LLM.
8038
+ * Invoke the fill_form tool using the LLM.
7999
8039
  *
8000
8040
  * Each call is stateless - the full form context is provided fresh each turn.
8001
8041
  * The form itself carries all state (filled values, remaining issues).
@@ -8006,20 +8046,22 @@ var LiveAgent = class {
8006
8046
  * @param maxPatches - Maximum patches to generate
8007
8047
  * @param previousRejections - Rejections from previous turn (helps LLM learn from mistakes)
8008
8048
  */
8009
- async generatePatches(issues, form, maxPatches, previousRejections) {
8049
+ async fillFormTool(issues, form, maxPatches, previousRejections) {
8010
8050
  const contextPrompt = buildContextPrompt(issues, form, maxPatches, previousRejections);
8011
8051
  let systemPrompt = buildSystemPrompt(form, this.targetRole, issues);
8012
8052
  if (this.systemPromptAddition) systemPrompt += "\n\n# Additional Context\n" + this.systemPromptAddition;
8013
8053
  if (this.enableWebSearch && this.provider && !this.webSearchTools) this.webSearchTools = loadWebSearchTools(this.provider);
8014
8054
  if (this.webSearchTools && Object.keys(this.webSearchTools).length > 0) systemPrompt += "\n\n" + WEB_SEARCH_INSTRUCTIONS;
8015
- const tools = wrapToolsWithCallbacks({
8016
- generatePatches: {
8017
- description: GENERATE_PATCHES_TOOL_DESCRIPTION,
8018
- inputSchema: zodSchema(z.object({ patches: z.array(PatchSchema).max(maxPatches).describe("Array of patches. Each patch sets a value for one field.") }))
8019
- },
8055
+ const fillFormToolDef = {
8056
+ description: FILL_FORM_TOOL_DESCRIPTION,
8057
+ inputSchema: zodSchema(z.object({ patches: z.array(PatchSchema).max(maxPatches).describe("Array of patches. Each patch sets a value for one field.") }))
8058
+ };
8059
+ const rawTools = {
8060
+ [FILL_FORM_TOOL_NAME]: fillFormToolDef,
8020
8061
  ...this.webSearchTools,
8021
8062
  ...this.additionalTools
8022
- }, this.callbacks);
8063
+ };
8064
+ const tools = wrapToolsWithCallbacks(rawTools, this.callbacks);
8023
8065
  const modelId = this.model.modelId ?? "unknown";
8024
8066
  if (this.callbacks?.onLlmCallStart) try {
8025
8067
  this.callbacks.onLlmCallStart({ model: modelId });
@@ -8043,7 +8085,7 @@ var LiveAgent = class {
8043
8085
  for (const step of result.steps) for (const toolCall of step.toolCalls) {
8044
8086
  const count = toolCallCounts.get(toolCall.toolName) ?? 0;
8045
8087
  toolCallCounts.set(toolCall.toolName, count + 1);
8046
- if (toolCall.toolName === "generatePatches" && "input" in toolCall) {
8088
+ if (toolCall.toolName === FILL_FORM_TOOL_NAME && "input" in toolCall) {
8047
8089
  const input = toolCall.input;
8048
8090
  patches.push(...input.patches);
8049
8091
  }
@@ -8055,6 +8097,7 @@ var LiveAgent = class {
8055
8097
  });
8056
8098
  const requiredRemaining = issues.filter((i) => i.severity === "required").length;
8057
8099
  const optionalRemaining = issues.filter((i) => i.severity === "recommended").length;
8100
+ const wire = buildWireFormat(systemPrompt, contextPrompt, rawTools, result);
8058
8101
  const stats = {
8059
8102
  inputTokens: result.usage?.inputTokens,
8060
8103
  outputTokens: result.usage?.outputTokens,
@@ -8068,7 +8111,8 @@ var LiveAgent = class {
8068
8111
  prompts: {
8069
8112
  system: systemPrompt,
8070
8113
  context: contextPrompt
8071
- }
8114
+ },
8115
+ wire
8072
8116
  };
8073
8117
  return {
8074
8118
  patches: patches.slice(0, maxPatches),
@@ -8077,6 +8121,66 @@ var LiveAgent = class {
8077
8121
  }
8078
8122
  };
8079
8123
  /**
8124
+ * Extract tool schemas from tools object for wire format logging.
8125
+ * Captures description and inputSchema for each tool.
8126
+ */
8127
+ function extractToolSchemas(tools) {
8128
+ const schemas = {};
8129
+ const sortedNames = Object.keys(tools).sort();
8130
+ for (const name$2 of sortedNames) {
8131
+ const tool$1 = tools[name$2];
8132
+ if (tool$1) schemas[name$2] = {
8133
+ description: tool$1.description ?? "",
8134
+ inputSchema: sortObjectKeys(tool$1.inputSchema ?? {})
8135
+ };
8136
+ }
8137
+ return schemas;
8138
+ }
8139
+ /**
8140
+ * Sort object keys recursively for deterministic serialization.
8141
+ * This ensures wire format is stable across runs for diffing.
8142
+ */
8143
+ function sortObjectKeys(obj) {
8144
+ if (obj === null || typeof obj !== "object") return obj;
8145
+ if (Array.isArray(obj)) return obj.map(sortObjectKeys);
8146
+ const sorted = {};
8147
+ for (const key of Object.keys(obj).sort()) sorted[key] = sortObjectKeys(obj[key]);
8148
+ return sorted;
8149
+ }
8150
+ /**
8151
+ * Build wire format from generateText result.
8152
+ * Captures complete request/response for session logging.
8153
+ *
8154
+ * Uses loose typing to handle AI SDK's complex result structure.
8155
+ */
8156
+ function buildWireFormat(systemPrompt, contextPrompt, tools, result) {
8157
+ const steps = result.steps.map((step) => ({
8158
+ toolCalls: step.toolCalls.map((tc) => ({
8159
+ toolName: tc.toolName,
8160
+ input: sortObjectKeys(tc.input)
8161
+ })),
8162
+ toolResults: (step.toolResults ?? []).map((tr) => ({
8163
+ toolName: tr.toolName,
8164
+ result: sortObjectKeys(tr.result)
8165
+ })),
8166
+ text: step.text ?? null
8167
+ }));
8168
+ return {
8169
+ request: {
8170
+ system: systemPrompt,
8171
+ prompt: contextPrompt,
8172
+ tools: extractToolSchemas(tools)
8173
+ },
8174
+ response: {
8175
+ steps,
8176
+ usage: {
8177
+ inputTokens: result.usage?.inputTokens ?? 0,
8178
+ outputTokens: result.usage?.outputTokens ?? 0
8179
+ }
8180
+ }
8181
+ };
8182
+ }
8183
+ /**
8080
8184
  * Extract doc blocks of a specific tag type for a given ref.
8081
8185
  */
8082
8186
  function getDocBlocks(docs, ref, tag) {
@@ -8147,8 +8251,9 @@ function buildContextPrompt(issues, form, maxPatches, previousRejections) {
8147
8251
  for (const rejection of previousRejections) {
8148
8252
  lines.push(`- **Error:** ${rejection.message}`);
8149
8253
  if (rejection.fieldKind) {
8254
+ lines.push(` **Correction:** This field is type "${rejection.fieldKind}". Use set_${rejection.fieldKind} instead.`);
8150
8255
  const hint = getPatchFormatHint(rejection.fieldKind, rejection.fieldId, rejection.columnIds);
8151
- lines.push(` **Use instead:** ${hint}`);
8256
+ lines.push(` **Correct format:** ${hint}`);
8152
8257
  }
8153
8258
  }
8154
8259
  lines.push("");
@@ -8164,7 +8269,7 @@ function buildContextPrompt(issues, form, maxPatches, previousRejections) {
8164
8269
  lines.push("");
8165
8270
  lines.push(ISSUES_HEADER);
8166
8271
  lines.push("");
8167
- lines.push(getIssuesIntro(maxPatches));
8272
+ lines.push(getIssuesIntro(issues.length));
8168
8273
  lines.push("");
8169
8274
  for (const issue of issues) {
8170
8275
  lines.push(`- **${issue.ref}** (${issue.scope}): ${issue.message}`);
@@ -8178,7 +8283,9 @@ function buildContextPrompt(issues, form, maxPatches, previousRejections) {
8178
8283
  lines.push(` Options: ${optionIds}`);
8179
8284
  }
8180
8285
  if (field.kind === "checkboxes" && "checkboxMode" in field) lines.push(` Mode: ${field.checkboxMode ?? "multi"}`);
8286
+ let columnIds;
8181
8287
  if (field.kind === "table" && "columns" in field && field.columns) {
8288
+ columnIds = field.columns.map((c) => c.id);
8182
8289
  const columnInfo = field.columns.map((c) => `${c.id}${c.required ? " (required)" : ""}`).join(", ");
8183
8290
  lines.push(` Columns: ${columnInfo}`);
8184
8291
  if (field.minRows !== void 0 || field.maxRows !== void 0) {
@@ -8188,11 +8295,15 @@ function buildContextPrompt(issues, form, maxPatches, previousRejections) {
8188
8295
  lines.push(` Rows: ${constraints.join(", ")}`);
8189
8296
  }
8190
8297
  }
8298
+ const patchHint = getPatchFormatHint(field.kind, field.id, columnIds);
8299
+ lines.push(` Set: ${patchHint}`);
8300
+ if (issue.severity === "required") lines.push(` This field is required.`);
8301
+ else lines.push(` Skip: { op: "skip_field", fieldId: "${field.id}", reason: "..." }`);
8191
8302
  }
8192
8303
  }
8193
8304
  lines.push("");
8194
8305
  }
8195
- lines.push(PATCH_FORMAT_INSTRUCTIONS);
8306
+ lines.push(GENERAL_INSTRUCTIONS);
8196
8307
  return lines.join("\n");
8197
8308
  }
8198
8309
  /**
@@ -8292,6 +8403,58 @@ function loadWebSearchTools(provider) {
8292
8403
  function createLiveAgent(config) {
8293
8404
  return new LiveAgent(config);
8294
8405
  }
8406
+ /**
8407
+ * Build wire format for mock sessions.
8408
+ *
8409
+ * This captures what WOULD be sent to the LLM in a mock session,
8410
+ * enabling git-based testing where prompt changes are visible in diffs.
8411
+ *
8412
+ * @param form - Current form state
8413
+ * @param issues - Issues being addressed
8414
+ * @param patches - Patches generated by mock agent
8415
+ * @param maxPatches - Max patches per turn
8416
+ * @param targetRole - Target role for instructions
8417
+ * @param previousRejections - Rejections from previous turn
8418
+ */
8419
+ function buildMockWireFormat(form, issues, patches, maxPatches, targetRole = AGENT_ROLE, previousRejections) {
8420
+ const systemPrompt = buildSystemPrompt(form, targetRole, issues);
8421
+ const contextPrompt = buildContextPrompt(issues, form, maxPatches, previousRejections);
8422
+ const tools = { [FILL_FORM_TOOL_NAME]: {
8423
+ description: FILL_FORM_TOOL_DESCRIPTION,
8424
+ inputSchema: sortObjectKeys({
8425
+ type: "object",
8426
+ properties: { patches: {
8427
+ type: "array",
8428
+ items: { $ref: "#/$defs/patch" },
8429
+ description: "Array of patches to apply to the form"
8430
+ } },
8431
+ required: ["patches"],
8432
+ $defs: { patch: { description: "A patch operation (see tool description for full schema)" } }
8433
+ })
8434
+ } };
8435
+ const steps = [{
8436
+ toolCalls: [{
8437
+ toolName: FILL_FORM_TOOL_NAME,
8438
+ input: sortObjectKeys({ patches })
8439
+ }],
8440
+ toolResults: [],
8441
+ text: null
8442
+ }];
8443
+ return {
8444
+ request: {
8445
+ system: systemPrompt,
8446
+ prompt: contextPrompt,
8447
+ tools
8448
+ },
8449
+ response: {
8450
+ steps,
8451
+ usage: {
8452
+ inputTokens: 0,
8453
+ outputTokens: 0
8454
+ }
8455
+ }
8456
+ };
8457
+ }
8295
8458
 
8296
8459
  //#endregion
8297
8460
  //#region src/harness/modelResolver.ts
@@ -8566,7 +8729,7 @@ async function fillForm(options) {
8566
8729
  issues: turnIssues
8567
8730
  });
8568
8731
  } catch {}
8569
- const { patches, stats } = await agent.generatePatches(turnIssues, form, maxPatchesPerTurn, previousRejections);
8732
+ const { patches, stats } = await agent.fillFormTool(turnIssues, form, maxPatchesPerTurn, previousRejections);
8570
8733
  if (options.callbacks?.onPatchesGenerated) try {
8571
8734
  options.callbacks.onPatchesGenerated({
8572
8735
  turnNumber: turnCount + 1,
@@ -8591,7 +8754,7 @@ async function fillForm(options) {
8591
8754
  contextPrompt: stats.prompts.context
8592
8755
  };
8593
8756
  }
8594
- stepResult = harness.apply(patches, turnIssues, llmStats, context);
8757
+ stepResult = harness.apply(patches, turnIssues, llmStats, context, stats?.wire);
8595
8758
  const actualPatchesApplied = stepResult.patchesApplied ?? patches.length;
8596
8759
  totalPatches += actualPatchesApplied;
8597
8760
  turnCount++;
@@ -8684,7 +8847,7 @@ async function runResearch(form, options) {
8684
8847
  let totalOutputTokens = 0;
8685
8848
  let stepResult = harness.step();
8686
8849
  while (!stepResult.isComplete && !harness.hasReachedMaxTurns()) {
8687
- const response = await agent.generatePatches(stepResult.issues, harness.getForm(), config.maxPatchesPerTurn);
8850
+ const response = await agent.fillFormTool(stepResult.issues, harness.getForm(), config.maxPatchesPerTurn);
8688
8851
  if (response.stats?.inputTokens) totalInputTokens += response.stats.inputTokens;
8689
8852
  if (response.stats?.outputTokens) totalOutputTokens += response.stats.outputTokens;
8690
8853
  stepResult = harness.apply(response.patches, stepResult.issues);
@@ -8764,7 +8927,7 @@ function validateResearchForm(form) {
8764
8927
  //#endregion
8765
8928
  //#region src/index.ts
8766
8929
  /** Markform version (injected at build time). */
8767
- const VERSION = "0.1.8";
8930
+ const VERSION = "0.1.9";
8768
8931
 
8769
8932
  //#endregion
8770
- export { ParseError$1 as A, serializeScopeRef as C, parseCellValue as D, parseForm as E, parseMarkdownTable as O, parseScopeRef as S, formToJsonSchema as T, findFieldById as _, resolveHarnessConfig as a, isFieldRef as b, getProviderNames as c, MockAgent as d, createMockAgent as f, coerceToFieldPatch as g, coerceInputContext as h, runResearch as i, parseRawTable as k, resolveModel as l, createHarness as m, isResearchForm as n, fillForm as o, FormHarness as p, validateResearchForm as r, getProviderInfo as s, VERSION as t, createLiveAgent as u, getFieldId as v, fieldToJsonSchema as w, isQualifiedRef as x, isCellRef as y };
8933
+ export { parseRawTable as A, parseScopeRef as C, parseForm as D, formToJsonSchema as E, parseCellValue as O, isQualifiedRef as S, fieldToJsonSchema as T, coerceToFieldPatch as _, resolveHarnessConfig as a, isCellRef as b, getProviderNames as c, createLiveAgent as d, MockAgent as f, coerceInputContext as g, createHarness as h, runResearch as i, ParseError$1 as j, parseMarkdownTable as k, resolveModel as l, FormHarness as m, isResearchForm as n, fillForm as o, createMockAgent as p, validateResearchForm as r, getProviderInfo as s, VERSION as t, buildMockWireFormat as u, findFieldById as v, serializeScopeRef as w, isFieldRef as x, getFieldId as y };
@@ -1385,12 +1385,12 @@ type IssueReason =
1385
1385
  | 'checkbox_incomplete' // Required checkboxes with non-terminal states
1386
1386
  | 'min_items_not_met' // String-list or multi-select below minimum
1387
1387
  // Severity: *recommended* (optional improvements)
1388
- | 'optional_empty'; // Optional field with no value
1388
+ | 'optional_unanswered'; // Optional field not yet addressed
1389
1389
 
1390
1390
  // Mapping from ValidationIssue to InspectIssue:
1391
1391
  // - ValidationIssue.severity='error' → InspectIssue.severity='required'
1392
1392
  // - ValidationIssue.severity='warning'/'info' → InspectIssue.severity='recommended'
1393
- // - Missing optional fields → severity='recommended', reason='optional_empty'
1393
+ // - Unanswered optional fields → severity='recommended', reason='optional_unanswered'
1394
1394
  ```
1395
1395
 
1396
1396
  #### StructureSummary and ProgressSummary
@@ -2695,7 +2695,7 @@ type.
2695
2695
  | `checkbox_incomplete` | 3 (required) / 2 (recommended) |
2696
2696
  | `validation_error` | 2 |
2697
2697
  | `min_items_not_met` | 2 |
2698
- | `optional_empty` | 1 |
2698
+ | `optional_unanswered` | 1 |
2699
2699
 
2700
2700
  **Total Score** = Field Priority Weight + Issue Type Score
2701
2701
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  markform:
3
3
  spec: MF/0.1
4
- title: Movie Research (Deep)
4
+ title: Movie Deep Research
5
5
  description: Comprehensive movie research form with ratings, box office, cast/crew, technical specs, streaming availability, and cultural analysis.
6
6
  run_mode: research
7
7
  roles:
@@ -40,7 +40,7 @@ markform:
40
40
  max_patches_per_turn: 15
41
41
  ---
42
42
 
43
- {% form id="movie_research_deep" title="Movie Research (Deep)" %}
43
+ {% form id="movie_research_deep" title="Movie Deep Research" %}
44
44
 
45
45
  {% description ref="movie_research_deep" %}
46
46
  Comprehensive movie research covering ratings from multiple sources, box office performance, full cast and crew, technical specifications, streaming availability, and cultural impact analysis.