markform 0.1.1 → 0.1.3

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.
Files changed (36) hide show
  1. package/DOCS.md +546 -0
  2. package/README.md +340 -71
  3. package/SPEC.md +2779 -0
  4. package/dist/ai-sdk.d.mts +2 -2
  5. package/dist/ai-sdk.mjs +5 -3
  6. package/dist/{apply-BQdd-fdx.mjs → apply-00UmzDKL.mjs} +849 -730
  7. package/dist/bin.mjs +6 -3
  8. package/dist/{cli-pjOiHgCW.mjs → cli-D--Lel-e.mjs} +1374 -428
  9. package/dist/cli.mjs +6 -3
  10. package/dist/{coreTypes--6etkcwb.d.mts → coreTypes-BXhhz9Iq.d.mts} +1946 -794
  11. package/dist/coreTypes-Dful87E0.mjs +537 -0
  12. package/dist/index.d.mts +116 -19
  13. package/dist/index.mjs +5 -3
  14. package/dist/session-Bqnwi9wp.mjs +110 -0
  15. package/dist/session-DdAtY2Ni.mjs +4 -0
  16. package/dist/shared-D7gf27Tr.mjs +3 -0
  17. package/dist/shared-N_s1M-_K.mjs +176 -0
  18. package/dist/src-Dm8jZ5dl.mjs +7587 -0
  19. package/examples/celebrity-deep-research/celebrity-deep-research.form.md +912 -0
  20. package/examples/earnings-analysis/earnings-analysis.form.md +6 -1
  21. package/examples/earnings-analysis/earnings-analysis.valid.ts +119 -59
  22. package/examples/movie-research/movie-research-basic.form.md +164 -0
  23. package/examples/movie-research/movie-research-deep.form.md +486 -0
  24. package/examples/movie-research/movie-research-minimal.form.md +54 -0
  25. package/examples/simple/simple-mock-filled.form.md +17 -13
  26. package/examples/simple/simple-skipped-filled.form.md +32 -9
  27. package/examples/simple/simple-with-skips.session.yaml +102 -143
  28. package/examples/simple/simple.form.md +13 -13
  29. package/examples/simple/simple.session.yaml +80 -69
  30. package/examples/startup-deep-research/startup-deep-research.form.md +60 -8
  31. package/examples/startup-research/startup-research-mock-filled.form.md +1 -1
  32. package/examples/startup-research/startup-research.form.md +1 -1
  33. package/package.json +10 -14
  34. package/dist/src-Cs4_9lWP.mjs +0 -2151
  35. package/examples/political-research/political-research.form.md +0 -233
  36. package/examples/political-research/political-research.mock.lincoln.form.md +0 -355
@@ -1,12 +1,17 @@
1
1
  ---
2
2
  markform:
3
- markform_version: "0.1.0"
3
+ spec: MF/0.1
4
+ title: Company Quarterly Analysis
5
+ description: Financial analysis with one user field (company) and agent-filled quarterly analysis sections.
4
6
  roles:
5
7
  - user
6
8
  - agent
7
9
  role_instructions:
8
10
  user: "Enter company identification (legal name, ticker, fiscal year) and the quarter you want analyzed."
9
11
  agent: "Complete the company profile and quarterly analysis based on the provided company context."
12
+ harness_config:
13
+ max_issues_per_turn: 5
14
+ max_patches_per_turn: 10
10
15
  ---
11
16
 
12
17
  {% form id="company_analysis" title="Company Quarterly Analysis Worksheet" %}
@@ -57,7 +57,14 @@ function getSingleSelectValue(values: Record<string, unknown>, fieldId: string):
57
57
  function minWords(ctx: ValidatorContext): ValidationIssue[] {
58
58
  const min = ctx.params.min as number;
59
59
  if (typeof min !== 'number') {
60
- return [{ severity: 'error', message: 'min_words requires "min" parameter', ref: ctx.targetId, source: 'code' }];
60
+ return [
61
+ {
62
+ severity: 'error',
63
+ message: 'min_words requires "min" parameter',
64
+ ref: ctx.targetId,
65
+ source: 'code',
66
+ },
67
+ ];
61
68
  }
62
69
 
63
70
  const value = getStringValue(ctx.values, ctx.targetId);
@@ -65,12 +72,14 @@ function minWords(ctx: ValidatorContext): ValidationIssue[] {
65
72
 
66
73
  const wordCount = countWords(value);
67
74
  if (wordCount < min) {
68
- return [{
69
- severity: 'error',
70
- message: `Field requires at least ${min} words (currently ${wordCount})`,
71
- ref: ctx.targetId,
72
- source: 'code',
73
- }];
75
+ return [
76
+ {
77
+ severity: 'error',
78
+ message: `Field requires at least ${min} words (currently ${wordCount})`,
79
+ ref: ctx.targetId,
80
+ source: 'code',
81
+ },
82
+ ];
74
83
  }
75
84
  return [];
76
85
  }
@@ -82,7 +91,14 @@ function minWords(ctx: ValidatorContext): ValidationIssue[] {
82
91
  function maxWords(ctx: ValidatorContext): ValidationIssue[] {
83
92
  const max = ctx.params.max as number;
84
93
  if (typeof max !== 'number') {
85
- return [{ severity: 'error', message: 'max_words requires "max" parameter', ref: ctx.targetId, source: 'code' }];
94
+ return [
95
+ {
96
+ severity: 'error',
97
+ message: 'max_words requires "max" parameter',
98
+ ref: ctx.targetId,
99
+ source: 'code',
100
+ },
101
+ ];
86
102
  }
87
103
 
88
104
  const value = getStringValue(ctx.values, ctx.targetId);
@@ -90,12 +106,14 @@ function maxWords(ctx: ValidatorContext): ValidationIssue[] {
90
106
 
91
107
  const wordCount = countWords(value);
92
108
  if (wordCount > max) {
93
- return [{
94
- severity: 'warning',
95
- message: `Field exceeds ${max} word limit (currently ${wordCount})`,
96
- ref: ctx.targetId,
97
- source: 'code',
98
- }];
109
+ return [
110
+ {
111
+ severity: 'warning',
112
+ message: `Field exceeds ${max} word limit (currently ${wordCount})`,
113
+ ref: ctx.targetId,
114
+ source: 'code',
115
+ },
116
+ ];
99
117
  }
100
118
  return [];
101
119
  }
@@ -110,22 +128,31 @@ function sumTo(ctx: ValidatorContext): ValidationIssue[] {
110
128
  const tolerance = (ctx.params.tolerance as number) ?? 0.1;
111
129
 
112
130
  if (!Array.isArray(fields)) {
113
- return [{ severity: 'error', message: 'sum_to requires "fields" array parameter', ref: ctx.targetId, source: 'code' }];
131
+ return [
132
+ {
133
+ severity: 'error',
134
+ message: 'sum_to requires "fields" array parameter',
135
+ ref: ctx.targetId,
136
+ source: 'code',
137
+ },
138
+ ];
114
139
  }
115
140
 
116
- const values = fields.map(fieldId => getNumberValue(ctx.values, fieldId) ?? 0);
141
+ const values = fields.map((fieldId) => getNumberValue(ctx.values, fieldId) ?? 0);
117
142
  const sum = values.reduce((a, b) => a + b, 0);
118
143
 
119
144
  // Only validate if at least one value is set
120
- if (values.every(v => v === 0)) return [];
145
+ if (values.every((v) => v === 0)) return [];
121
146
 
122
147
  if (Math.abs(sum - target) > tolerance) {
123
- return [{
124
- severity: 'error',
125
- message: `Fields must sum to ${target}% (currently ${sum.toFixed(1)}%)`,
126
- ref: fields[0],
127
- source: 'code',
128
- }];
148
+ return [
149
+ {
150
+ severity: 'error',
151
+ message: `Fields must sum to ${target}% (currently ${sum.toFixed(1)}%)`,
152
+ ref: fields[0],
153
+ source: 'code',
154
+ },
155
+ ];
129
156
  }
130
157
  return [];
131
158
  }
@@ -140,25 +167,31 @@ function sumToPercentList(ctx: ValidatorContext): ValidationIssue[] {
140
167
 
141
168
  if (items.length === 0) return [];
142
169
 
143
- const percentages = items.map(item => extractPercentage(item)).filter((p): p is number => p !== null);
170
+ const percentages = items
171
+ .map((item) => extractPercentage(item))
172
+ .filter((p): p is number => p !== null);
144
173
 
145
174
  if (percentages.length === 0) {
146
- return [{
147
- severity: 'warning',
148
- message: 'Items should include percentages (format: "Label: XX%")',
149
- ref: ctx.targetId,
150
- source: 'code',
151
- }];
175
+ return [
176
+ {
177
+ severity: 'warning',
178
+ message: 'Items should include percentages (format: "Label: XX%")',
179
+ ref: ctx.targetId,
180
+ source: 'code',
181
+ },
182
+ ];
152
183
  }
153
184
 
154
185
  const sum = percentages.reduce((a, b) => a + b, 0);
155
186
  if (Math.abs(sum - target) > 0.1) {
156
- return [{
157
- severity: 'warning',
158
- message: `Items should sum to ${target}% (currently ${sum.toFixed(1)}%)`,
159
- ref: ctx.targetId,
160
- source: 'code',
161
- }];
187
+ return [
188
+ {
189
+ severity: 'warning',
190
+ message: `Items should sum to ${target}% (currently ${sum.toFixed(1)}%)`,
191
+ ref: ctx.targetId,
192
+ source: 'code',
193
+ },
194
+ ];
162
195
  }
163
196
  return [];
164
197
  }
@@ -172,7 +205,14 @@ function requiredIf(ctx: ValidatorContext): ValidationIssue[] {
172
205
  const targetField = (ctx.params.then as string) ?? ctx.targetId;
173
206
 
174
207
  if (!triggerField) {
175
- return [{ severity: 'error', message: 'required_if requires "when" parameter', ref: ctx.targetId, source: 'code' }];
208
+ return [
209
+ {
210
+ severity: 'error',
211
+ message: 'required_if requires "when" parameter',
212
+ ref: ctx.targetId,
213
+ source: 'code',
214
+ },
215
+ ];
176
216
  }
177
217
 
178
218
  const trigger = ctx.values[triggerField] as Record<string, unknown> | undefined;
@@ -189,12 +229,14 @@ function requiredIf(ctx: ValidatorContext): ValidationIssue[] {
189
229
  (target.kind === 'number' && target.value == null);
190
230
 
191
231
  if (triggerHasValue && targetEmpty) {
192
- return [{
193
- severity: 'error',
194
- message: `This field is required when ${triggerField} has a value`,
195
- ref: targetField,
196
- source: 'code',
197
- }];
232
+ return [
233
+ {
234
+ severity: 'error',
235
+ message: `This field is required when ${triggerField} has a value`,
236
+ ref: targetField,
237
+ source: 'code',
238
+ },
239
+ ];
198
240
  }
199
241
  return [];
200
242
  }
@@ -209,19 +251,28 @@ function requiredIfEquals(ctx: ValidatorContext): ValidationIssue[] {
209
251
  const targetField = (ctx.params.then as string) ?? ctx.targetId;
210
252
 
211
253
  if (!triggerField || expectedValue === undefined) {
212
- return [{ severity: 'error', message: 'required_if_equals requires "when" and "equals" parameters', ref: ctx.targetId, source: 'code' }];
254
+ return [
255
+ {
256
+ severity: 'error',
257
+ message: 'required_if_equals requires "when" and "equals" parameters',
258
+ ref: ctx.targetId,
259
+ source: 'code',
260
+ },
261
+ ];
213
262
  }
214
263
 
215
264
  const triggerValue = getSingleSelectValue(ctx.values, triggerField);
216
265
  const target = getStringValue(ctx.values, targetField);
217
266
 
218
267
  if (triggerValue === expectedValue && (!target || target.trim().length === 0)) {
219
- return [{
220
- severity: 'error',
221
- message: `This field is required when ${triggerField} is "${expectedValue}"`,
222
- ref: targetField,
223
- source: 'code',
224
- }];
268
+ return [
269
+ {
270
+ severity: 'error',
271
+ message: `This field is required when ${triggerField} is "${expectedValue}"`,
272
+ ref: targetField,
273
+ source: 'code',
274
+ },
275
+ ];
225
276
  }
226
277
  return [];
227
278
  }
@@ -232,26 +283,35 @@ function requiredIfEquals(ctx: ValidatorContext): ValidationIssue[] {
232
283
  */
233
284
  function itemFormat(ctx: ValidatorContext): ValidationIssue[] {
234
285
  const pattern = ctx.params.pattern as string;
235
- const example = ctx.params.example as string ?? '';
286
+ const example = (ctx.params.example as string) ?? '';
236
287
 
237
288
  if (!pattern) {
238
- return [{ severity: 'error', message: 'item_format requires "pattern" parameter', ref: ctx.targetId, source: 'code' }];
289
+ return [
290
+ {
291
+ severity: 'error',
292
+ message: 'item_format requires "pattern" parameter',
293
+ ref: ctx.targetId,
294
+ source: 'code',
295
+ },
296
+ ];
239
297
  }
240
298
 
241
299
  const items = getStringListItems(ctx.values, ctx.targetId);
242
300
  if (items.length === 0) return [];
243
301
 
244
302
  const regex = new RegExp(pattern);
245
- const malformed = items.filter(item => !regex.test(item));
303
+ const malformed = items.filter((item) => !regex.test(item));
246
304
 
247
305
  if (malformed.length > 0) {
248
306
  const hint = example ? ` Expected format: "${example}"` : '';
249
- return [{
250
- severity: 'warning',
251
- message: `${malformed.length} item(s) don't match expected format.${hint}`,
252
- ref: ctx.targetId,
253
- source: 'code',
254
- }];
307
+ return [
308
+ {
309
+ severity: 'warning',
310
+ message: `${malformed.length} item(s) don't match expected format.${hint}`,
311
+ ref: ctx.targetId,
312
+ source: 'code',
313
+ },
314
+ ];
255
315
  }
256
316
  return [];
257
317
  }
@@ -0,0 +1,164 @@
1
+ ---
2
+ markform:
3
+ spec: MF/0.1
4
+ title: Movie Research (Basic)
5
+ description: Standard movie research form pulling ratings and key stats from IMDB, Rotten Tomatoes, and Metacritic.
6
+ roles:
7
+ - user
8
+ - agent
9
+ role_instructions:
10
+ user: "Enter the movie title and optionally the year for disambiguation."
11
+ agent: |
12
+ Research and fill in all fields for the specified movie.
13
+ Guidelines:
14
+ 1. WORKFLOW - Complete sections in order:
15
+ - First identify the movie title
16
+ - Then find all source URLs (verify you have the right movie on each site)
17
+ - Then fill in details (year, directors, ratings) from those sources
18
+ 2. PRIMARY SOURCES:
19
+ - IMDB (imdb.com) for ratings, runtime, and technical details
20
+ - Rotten Tomatoes (rottentomatoes.com) for Tomatometer and Audience Score
21
+ - Metacritic (metacritic.com) for Metascore
22
+ 3. Use the EXACT numeric scores from each source - don't average or interpret
23
+ 4. Skip fields if any scores are unavailable (older films may lack some metrics)
24
+ 5. Use the tool to add notes if there is missing, confusing, or unclear information
25
+ in the values you provide.
26
+ harness_config:
27
+ max_issues_per_turn: 3
28
+ max_patches_per_turn: 8
29
+ ---
30
+
31
+ {% form id="movie_research_basic" title="Movie Research (Basic)" %}
32
+
33
+ {% description ref="movie_research_basic" %}
34
+ Standard research form for gathering ratings and key statistics for any film. Pulls from IMDB, Rotten Tomatoes, and Metacritic.
35
+ {% /description %}
36
+
37
+ {% field-group id="movie_input" title="Movie Identification" %}
38
+
39
+ {% string-field id="movie" label="Movie" role="user" required=true minLength=1 maxLength=300 %}{% /string-field %}
40
+
41
+ {% instructions ref="movie" %}
42
+ Enter the movie title (add any details to help identify, like "Barbie 2023" or "the Batman movie with Robert Pattinson")
43
+ {% /instructions %}
44
+
45
+ {% /field-group %}
46
+
47
+ {% field-group id="title_identification" title="Title Identification" %}
48
+
49
+ {% string-field id="full_title" label="Full Title" role="agent" required=true %}{% /string-field %}
50
+
51
+ {% instructions ref="full_title" %}
52
+ Look up what film the user had in mind and fill in the official title including subtitle if any (e.g., "The Lord of the Rings: The Fellowship of the Ring").
53
+ {% /instructions %}
54
+
55
+ {% /field-group %}
56
+
57
+ {% field-group id="sources" title="Sources" %}
58
+
59
+ {% url-field id="imdb_url" label="IMDB URL" role="agent" required=true %}{% /url-field %}
60
+
61
+ {% instructions ref="imdb_url" %}
62
+ Direct link to the movie's IMDB page (e.g., https://www.imdb.com/title/tt0111161/).
63
+ {% /instructions %}
64
+
65
+ {% url-field id="rt_url" label="Rotten Tomatoes URL" role="agent" %}{% /url-field %}
66
+
67
+ {% instructions ref="rt_url" %}
68
+ Direct link to the movie's Rotten Tomatoes page.
69
+ {% /instructions %}
70
+
71
+ {% url-field id="metacritic_url" label="Metacritic URL" role="agent" %}{% /url-field %}
72
+
73
+ {% instructions ref="metacritic_url" %}
74
+ Direct link to the movie's Metacritic page.
75
+ {% /instructions %}
76
+
77
+ {% /field-group %}
78
+
79
+ {% field-group id="basic_details" title="Basic Details" %}
80
+
81
+ {% number-field id="year" label="Release Year" role="agent" required=true min=1888 max=2030 %}{% /number-field %}
82
+
83
+ {% string-list id="directors" label="Director(s)" role="agent" required=true %}{% /string-list %}
84
+
85
+ {% instructions ref="directors" %}
86
+ One director per line. Most films have one; some have two or more co-directors.
87
+ {% /instructions %}
88
+
89
+ {% number-field id="runtime_minutes" label="Runtime (minutes)" role="agent" min=1 max=1000 %}{% /number-field %}
90
+
91
+ {% single-select id="mpaa_rating" label="MPAA Rating" role="agent" %}
92
+ - [ ] G {% #g %}
93
+ - [ ] PG {% #pg %}
94
+ - [ ] PG-13 {% #pg_13 %}
95
+ - [ ] R {% #r %}
96
+ - [ ] NC-17 {% #nc_17 %}
97
+ - [ ] NR/Unrated {% #nr %}
98
+ {% /single-select %}
99
+
100
+ {% /field-group %}
101
+
102
+ {% field-group id="imdb_ratings" title="IMDB Ratings" %}
103
+
104
+ {% number-field id="imdb_rating" label="IMDB Rating" role="agent" min=1.0 max=10.0 %}{% /number-field %}
105
+
106
+ {% instructions ref="imdb_rating" %}
107
+ IMDB user rating (1.0-10.0 scale).
108
+ {% /instructions %}
109
+
110
+ {% number-field id="imdb_votes" label="IMDB Vote Count" role="agent" min=0 %}{% /number-field %}
111
+
112
+ {% instructions ref="imdb_votes" %}
113
+ Number of IMDB user votes (e.g., 2800000 for a popular film).
114
+ {% /instructions %}
115
+
116
+ {% /field-group %}
117
+
118
+ {% field-group id="rotten_tomatoes_ratings" title="Rotten Tomatoes Ratings" %}
119
+
120
+ {% number-field id="rt_critics_score" label="Tomatometer (Critics)" role="agent" min=0 max=100 %}{% /number-field %}
121
+
122
+ {% instructions ref="rt_critics_score" %}
123
+ Tomatometer percentage (0-100).
124
+ {% /instructions %}
125
+
126
+ {% number-field id="rt_critics_count" label="Critics Review Count" role="agent" min=0 %}{% /number-field %}
127
+
128
+ {% number-field id="rt_audience_score" label="Audience Score" role="agent" min=0 max=100 %}{% /number-field %}
129
+
130
+ {% instructions ref="rt_audience_score" %}
131
+ Audience Score percentage (0-100).
132
+ {% /instructions %}
133
+
134
+ {% /field-group %}
135
+
136
+ {% field-group id="metacritic_ratings" title="Metacritic Ratings" %}
137
+
138
+ {% number-field id="metacritic_score" label="Metacritic Score" role="agent" min=0 max=100 %}{% /number-field %}
139
+
140
+ {% instructions ref="metacritic_score" %}
141
+ Metascore (0-100 scale). Leave empty if not available.
142
+ {% /instructions %}
143
+
144
+ {% /field-group %}
145
+
146
+ {% field-group id="summary" title="Summary" %}
147
+
148
+ {% string-field id="logline" label="One-Line Summary" role="agent" maxLength=300 %}{% /string-field %}
149
+
150
+ {% instructions ref="logline" %}
151
+ Brief plot summary in 1-2 sentences, no spoilers.
152
+ {% /instructions %}
153
+
154
+ {% string-list id="notable_awards" label="Notable Awards" role="agent" %}{% /string-list %}
155
+
156
+ {% instructions ref="notable_awards" %}
157
+ Major awards won. One per line.
158
+ Format: Award | Category | Year
159
+ Example: "Oscar | Best Picture | 1995"
160
+ {% /instructions %}
161
+
162
+ {% /field-group %}
163
+
164
+ {% /form %}