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.
- package/README.md +44 -55
- package/dist/ai-sdk.d.mts +1 -1
- package/dist/ai-sdk.mjs +2 -2
- package/dist/{apply-BUU2QcJ2.mjs → apply-B2kt6C2z.mjs} +34 -12
- package/dist/bin.mjs +1 -1
- package/dist/{cli-BZh25bvy.mjs → cli-Dt_PlYi_.mjs} +498 -57
- package/dist/cli.mjs +1 -1
- package/dist/{coreTypes-DJtu8OOp.mjs → coreTypes-B1oI7qvV.mjs} +36 -3
- package/dist/{coreTypes-BSPJ9H27.d.mts → coreTypes-JCPm418M.d.mts} +215 -9
- package/dist/index.d.mts +16 -9
- package/dist/index.mjs +5 -5
- package/dist/{session-DSTNiHza.mjs → session-CzCh6JeY.mjs} +1 -1
- package/dist/{session-CmHdAPyg.mjs → session-Dxqwt0RC.mjs} +3 -3
- package/dist/{shared-C9yW5FLZ.mjs → shared-CNqwaxUt.mjs} +1 -1
- package/dist/{shared-DQ6y3Ggc.mjs → shared-D3dNi-Gn.mjs} +1 -1
- package/dist/{src-kUggXhN1.mjs → src-DFsC5wwy.mjs} +203 -40
- package/docs/markform-spec.md +3 -3
- package/examples/movie-research/{movie-research-deep.form.md → movie-deep-research.form.md} +2 -2
- package/examples/rejection-test/rejection-test.session.yaml +446 -0
- package/examples/simple/simple-with-skips.session.yaml +1966 -18
- package/examples/simple/simple.session.yaml +1979 -18
- package/package.json +1 -1
- package/examples/earnings-analysis/earnings-analysis.form.md +0 -159
- package/examples/earnings-analysis/earnings-analysis.raw.md +0 -801
- package/examples/earnings-analysis/earnings-analysis.valid.ts +0 -198
- package/examples/movie-research/movie-research-basic.form.md +0 -169
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { L as PatchSchema, V as RunModeSchema } from "./coreTypes-
|
|
3
|
-
import { C as
|
|
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
|
-
*
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
7909
|
+
* @param issueCount - Actual number of issues shown
|
|
7893
7910
|
*/
|
|
7894
|
-
function getIssuesIntro(
|
|
7895
|
-
return `You need to address
|
|
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
|
|
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 = [
|
|
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
|
-
*
|
|
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
|
|
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
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
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
|
-
}
|
|
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 ===
|
|
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(` **
|
|
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(
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
8930
|
+
const VERSION = "0.1.9";
|
|
8768
8931
|
|
|
8769
8932
|
//#endregion
|
|
8770
|
-
export {
|
|
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 };
|
package/docs/markform-spec.md
CHANGED
|
@@ -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
|
-
| '
|
|
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
|
-
// -
|
|
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
|
-
| `
|
|
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
|
|
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
|
|
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.
|