markform 0.1.4 → 0.1.5
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 +40 -53
- package/dist/ai-sdk.d.mts +1 -1
- package/dist/ai-sdk.mjs +1 -1
- package/dist/{apply-C54EMAJ1.mjs → apply-BCCiJzQr.mjs} +3 -3
- package/dist/bin.mjs +3 -3
- package/dist/{cli-BhWhn6L9.mjs → cli-D469amuk.mjs} +5 -11
- package/dist/cli.mjs +3 -3
- package/dist/{coreTypes-cbNTYAcb.d.mts → coreTypes-9XZSNOv6.d.mts} +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{src-BNh7Cx9P.mjs → src-Df0XX7UB.mjs} +19 -6
- package/docs/markform-reference.md +19 -19
- package/docs/markform-spec.md +20 -20
- package/examples/earnings-analysis/earnings-analysis.form.md +86 -808
- package/examples/earnings-analysis/earnings-analysis.valid.ts +16 -148
- package/examples/movie-research/movie-research-basic.form.md +16 -16
- package/examples/movie-research/movie-research-deep.form.md +36 -36
- package/examples/movie-research/movie-research-minimal.form.md +4 -4
- package/examples/simple/simple-mock-filled.form.md +16 -16
- package/examples/simple/simple-skipped-filled.form.md +16 -16
- package/examples/simple/simple-with-skips.session.yaml +3 -3
- package/examples/simple/simple.form.md +16 -16
- package/examples/simple/simple.session.yaml +3 -3
- package/examples/startup-deep-research/startup-deep-research.form.md +22 -22
- package/examples/startup-research/startup-research-mock-filled.form.md +12 -12
- package/examples/startup-research/startup-research.form.md +12 -12
- package/package.json +1 -1
- package/examples/celebrity-deep-research/celebrity-deep-research.form.md +0 -967
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* These validators demonstrate parameterized validation patterns.
|
|
5
5
|
* Parameters are passed via ctx.params from the validate attribute:
|
|
6
6
|
*
|
|
7
|
-
* validate=[{id: "min_words", min:
|
|
7
|
+
* validate=[{id: "min_words", min: 20}]
|
|
8
8
|
*
|
|
9
|
-
* The validator receives { min:
|
|
9
|
+
* The validator receives { min: 20 } in ctx.params.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { ValidatorContext, ValidationIssue } from 'markform';
|
|
@@ -28,27 +28,17 @@ function getStringValue(values: Record<string, unknown>, fieldId: string): strin
|
|
|
28
28
|
return field?.kind === 'string' && field.value ? field.value : null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function getNumberValue(values: Record<string, unknown>, fieldId: string): number | null {
|
|
32
|
-
const field = values[fieldId] as { kind: string; value?: number | null } | undefined;
|
|
33
|
-
return field?.kind === 'number' && field.value != null ? field.value : null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
31
|
function getStringListItems(values: Record<string, unknown>, fieldId: string): string[] {
|
|
37
32
|
const field = values[fieldId] as { kind: string; items?: string[] } | undefined;
|
|
38
33
|
return field?.kind === 'string_list' && field.items ? field.items : [];
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
function getMultiSelectSelections(values: Record<string, unknown>, fieldId: string): string[] {
|
|
42
|
-
const field = values[fieldId] as { kind: string; selected?: string[] } | undefined;
|
|
43
|
-
return field?.kind === 'multi_select' && field.selected ? field.selected : [];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
36
|
function getSingleSelectValue(values: Record<string, unknown>, fieldId: string): string | null {
|
|
47
37
|
const field = values[fieldId] as { kind: string; selected?: string | null } | undefined;
|
|
48
38
|
return field?.kind === 'single_select' && field.selected ? field.selected : null;
|
|
49
39
|
}
|
|
50
40
|
|
|
51
|
-
//
|
|
41
|
+
// Validators
|
|
52
42
|
|
|
53
43
|
/**
|
|
54
44
|
* Validate minimum word count.
|
|
@@ -118,45 +108,6 @@ function maxWords(ctx: ValidatorContext): ValidationIssue[] {
|
|
|
118
108
|
return [];
|
|
119
109
|
}
|
|
120
110
|
|
|
121
|
-
/**
|
|
122
|
-
* Validate that specified number fields sum to a target.
|
|
123
|
-
* Params: { fields: string[], target?: number, tolerance?: number }
|
|
124
|
-
*/
|
|
125
|
-
function sumTo(ctx: ValidatorContext): ValidationIssue[] {
|
|
126
|
-
const fields = ctx.params.fields as string[];
|
|
127
|
-
const target = (ctx.params.target as number) ?? 100;
|
|
128
|
-
const tolerance = (ctx.params.tolerance as number) ?? 0.1;
|
|
129
|
-
|
|
130
|
-
if (!Array.isArray(fields)) {
|
|
131
|
-
return [
|
|
132
|
-
{
|
|
133
|
-
severity: 'error',
|
|
134
|
-
message: 'sum_to requires "fields" array parameter',
|
|
135
|
-
ref: ctx.targetId,
|
|
136
|
-
source: 'code',
|
|
137
|
-
},
|
|
138
|
-
];
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const values = fields.map((fieldId) => getNumberValue(ctx.values, fieldId) ?? 0);
|
|
142
|
-
const sum = values.reduce((a, b) => a + b, 0);
|
|
143
|
-
|
|
144
|
-
// Only validate if at least one value is set
|
|
145
|
-
if (values.every((v) => v === 0)) return [];
|
|
146
|
-
|
|
147
|
-
if (Math.abs(sum - target) > tolerance) {
|
|
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
|
-
];
|
|
156
|
-
}
|
|
157
|
-
return [];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
111
|
/**
|
|
161
112
|
* Validate that string-list items with "Label: XX%" format sum to target.
|
|
162
113
|
* Params: { target?: number }
|
|
@@ -197,117 +148,38 @@ function sumToPercentList(ctx: ValidatorContext): ValidationIssue[] {
|
|
|
197
148
|
}
|
|
198
149
|
|
|
199
150
|
/**
|
|
200
|
-
* Require field when another field has
|
|
201
|
-
* Params: { when: string
|
|
151
|
+
* Require field when another field has any value set.
|
|
152
|
+
* Params: { when: string }
|
|
202
153
|
*/
|
|
203
|
-
function
|
|
154
|
+
function requiredIfSet(ctx: ValidatorContext): ValidationIssue[] {
|
|
204
155
|
const triggerField = ctx.params.when as string;
|
|
205
|
-
const targetField = (ctx.params.then as string) ?? ctx.targetId;
|
|
206
156
|
|
|
207
157
|
if (!triggerField) {
|
|
208
158
|
return [
|
|
209
159
|
{
|
|
210
160
|
severity: 'error',
|
|
211
|
-
message: '
|
|
161
|
+
message: 'required_if_set requires "when" parameter',
|
|
212
162
|
ref: ctx.targetId,
|
|
213
163
|
source: 'code',
|
|
214
164
|
},
|
|
215
165
|
];
|
|
216
166
|
}
|
|
217
167
|
|
|
218
|
-
|
|
219
|
-
const target = ctx.values[targetField] as Record<string, unknown> | undefined;
|
|
220
|
-
|
|
168
|
+
// Check if trigger field has a value
|
|
221
169
|
const triggerHasValue =
|
|
222
|
-
(
|
|
223
|
-
(
|
|
224
|
-
(
|
|
170
|
+
getStringValue(ctx.values, triggerField) !== null ||
|
|
171
|
+
getSingleSelectValue(ctx.values, triggerField) !== null ||
|
|
172
|
+
getStringListItems(ctx.values, triggerField).length > 0;
|
|
225
173
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
(target.kind === 'number' && target.value == null);
|
|
174
|
+
// Check if target field is empty
|
|
175
|
+
const targetValue = getStringValue(ctx.values, ctx.targetId);
|
|
176
|
+
const targetEmpty = !targetValue || targetValue.trim().length === 0;
|
|
230
177
|
|
|
231
178
|
if (triggerHasValue && targetEmpty) {
|
|
232
179
|
return [
|
|
233
180
|
{
|
|
234
181
|
severity: 'error',
|
|
235
|
-
message: `This field is required when ${triggerField} has a value`,
|
|
236
|
-
ref: targetField,
|
|
237
|
-
source: 'code',
|
|
238
|
-
},
|
|
239
|
-
];
|
|
240
|
-
}
|
|
241
|
-
return [];
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Require field when another field equals a specific value.
|
|
246
|
-
* Params: { when: string, equals: string, then?: string }
|
|
247
|
-
*/
|
|
248
|
-
function requiredIfEquals(ctx: ValidatorContext): ValidationIssue[] {
|
|
249
|
-
const triggerField = ctx.params.when as string;
|
|
250
|
-
const expectedValue = ctx.params.equals as string;
|
|
251
|
-
const targetField = (ctx.params.then as string) ?? ctx.targetId;
|
|
252
|
-
|
|
253
|
-
if (!triggerField || expectedValue === undefined) {
|
|
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
|
-
];
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const triggerValue = getSingleSelectValue(ctx.values, triggerField);
|
|
265
|
-
const target = getStringValue(ctx.values, targetField);
|
|
266
|
-
|
|
267
|
-
if (triggerValue === expectedValue && (!target || target.trim().length === 0)) {
|
|
268
|
-
return [
|
|
269
|
-
{
|
|
270
|
-
severity: 'error',
|
|
271
|
-
message: `This field is required when ${triggerField} is "${expectedValue}"`,
|
|
272
|
-
ref: targetField,
|
|
273
|
-
source: 'code',
|
|
274
|
-
},
|
|
275
|
-
];
|
|
276
|
-
}
|
|
277
|
-
return [];
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Validate that list items match a regex pattern.
|
|
282
|
-
* Params: { pattern: string, example?: string }
|
|
283
|
-
*/
|
|
284
|
-
function itemFormat(ctx: ValidatorContext): ValidationIssue[] {
|
|
285
|
-
const pattern = ctx.params.pattern as string;
|
|
286
|
-
const example = (ctx.params.example as string) ?? '';
|
|
287
|
-
|
|
288
|
-
if (!pattern) {
|
|
289
|
-
return [
|
|
290
|
-
{
|
|
291
|
-
severity: 'error',
|
|
292
|
-
message: 'item_format requires "pattern" parameter',
|
|
293
|
-
ref: ctx.targetId,
|
|
294
|
-
source: 'code',
|
|
295
|
-
},
|
|
296
|
-
];
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const items = getStringListItems(ctx.values, ctx.targetId);
|
|
300
|
-
if (items.length === 0) return [];
|
|
301
|
-
|
|
302
|
-
const regex = new RegExp(pattern);
|
|
303
|
-
const malformed = items.filter((item) => !regex.test(item));
|
|
304
|
-
|
|
305
|
-
if (malformed.length > 0) {
|
|
306
|
-
const hint = example ? ` Expected format: "${example}"` : '';
|
|
307
|
-
return [
|
|
308
|
-
{
|
|
309
|
-
severity: 'warning',
|
|
310
|
-
message: `${malformed.length} item(s) don't match expected format.${hint}`,
|
|
182
|
+
message: `This field is required when "${triggerField}" has a value`,
|
|
311
183
|
ref: ctx.targetId,
|
|
312
184
|
source: 'code',
|
|
313
185
|
},
|
|
@@ -319,12 +191,8 @@ function itemFormat(ctx: ValidatorContext): ValidationIssue[] {
|
|
|
319
191
|
// Exported Validators Registry
|
|
320
192
|
|
|
321
193
|
export const validators: Record<string, (ctx: ValidatorContext) => ValidationIssue[]> = {
|
|
322
|
-
// Parameterized validators
|
|
323
194
|
min_words: minWords,
|
|
324
195
|
max_words: maxWords,
|
|
325
|
-
sum_to: sumTo,
|
|
326
196
|
sum_to_percent_list: sumToPercentList,
|
|
327
|
-
|
|
328
|
-
required_if_equals: requiredIfEquals,
|
|
329
|
-
item_format: itemFormat,
|
|
197
|
+
required_if_set: requiredIfSet,
|
|
330
198
|
};
|
|
@@ -34,7 +34,7 @@ markform:
|
|
|
34
34
|
Standard research form for gathering ratings and key statistics for any film. Pulls from IMDB, Rotten Tomatoes, and Metacritic.
|
|
35
35
|
{% /description %}
|
|
36
36
|
|
|
37
|
-
{%
|
|
37
|
+
{% group id="movie_input" title="Movie Identification" %}
|
|
38
38
|
|
|
39
39
|
{% field kind="string" id="movie" label="Movie" role="user" required=true minLength=1 maxLength=300 %}{% /field %}
|
|
40
40
|
|
|
@@ -42,9 +42,9 @@ Standard research form for gathering ratings and key statistics for any film. Pu
|
|
|
42
42
|
Enter the movie title (add any details to help identify, like "Barbie 2023" or "the Batman movie with Robert Pattinson")
|
|
43
43
|
{% /instructions %}
|
|
44
44
|
|
|
45
|
-
{% /
|
|
45
|
+
{% /group %}
|
|
46
46
|
|
|
47
|
-
{%
|
|
47
|
+
{% group id="title_identification" title="Title Identification" %}
|
|
48
48
|
|
|
49
49
|
{% field kind="string" id="full_title" label="Full Title" role="agent" required=true %}{% /field %}
|
|
50
50
|
|
|
@@ -52,9 +52,9 @@ Enter the movie title (add any details to help identify, like "Barbie 2023" or "
|
|
|
52
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
53
|
{% /instructions %}
|
|
54
54
|
|
|
55
|
-
{% /
|
|
55
|
+
{% /group %}
|
|
56
56
|
|
|
57
|
-
{%
|
|
57
|
+
{% group id="sources" title="Sources" %}
|
|
58
58
|
|
|
59
59
|
{% field kind="url" id="imdb_url" label="IMDB URL" role="agent" required=true %}{% /field %}
|
|
60
60
|
|
|
@@ -74,9 +74,9 @@ Direct link to the movie's Rotten Tomatoes page.
|
|
|
74
74
|
Direct link to the movie's Metacritic page.
|
|
75
75
|
{% /instructions %}
|
|
76
76
|
|
|
77
|
-
{% /
|
|
77
|
+
{% /group %}
|
|
78
78
|
|
|
79
|
-
{%
|
|
79
|
+
{% group id="basic_details" title="Basic Details" %}
|
|
80
80
|
|
|
81
81
|
{% field kind="number" id="year" label="Release Year" role="agent" required=true min=1888 max=2030 %}{% /field %}
|
|
82
82
|
|
|
@@ -97,9 +97,9 @@ One director per line. Most films have one; some have two or more co-directors.
|
|
|
97
97
|
- [ ] NR/Unrated {% #nr %}
|
|
98
98
|
{% /field %}
|
|
99
99
|
|
|
100
|
-
{% /
|
|
100
|
+
{% /group %}
|
|
101
101
|
|
|
102
|
-
{%
|
|
102
|
+
{% group id="imdb_ratings" title="IMDB Ratings" %}
|
|
103
103
|
|
|
104
104
|
{% field kind="number" id="imdb_rating" label="IMDB Rating" role="agent" min=1.0 max=10.0 %}{% /field %}
|
|
105
105
|
|
|
@@ -113,9 +113,9 @@ IMDB user rating (1.0-10.0 scale).
|
|
|
113
113
|
Number of IMDB user votes (e.g., 2800000 for a popular film).
|
|
114
114
|
{% /instructions %}
|
|
115
115
|
|
|
116
|
-
{% /
|
|
116
|
+
{% /group %}
|
|
117
117
|
|
|
118
|
-
{%
|
|
118
|
+
{% group id="rotten_tomatoes_ratings" title="Rotten Tomatoes Ratings" %}
|
|
119
119
|
|
|
120
120
|
{% field kind="number" id="rt_critics_score" label="Tomatometer (Critics)" role="agent" min=0 max=100 %}{% /field %}
|
|
121
121
|
|
|
@@ -131,9 +131,9 @@ Tomatometer percentage (0-100).
|
|
|
131
131
|
Audience Score percentage (0-100).
|
|
132
132
|
{% /instructions %}
|
|
133
133
|
|
|
134
|
-
{% /
|
|
134
|
+
{% /group %}
|
|
135
135
|
|
|
136
|
-
{%
|
|
136
|
+
{% group id="metacritic_ratings" title="Metacritic Ratings" %}
|
|
137
137
|
|
|
138
138
|
{% field kind="number" id="metacritic_score" label="Metacritic Score" role="agent" min=0 max=100 %}{% /field %}
|
|
139
139
|
|
|
@@ -141,9 +141,9 @@ Audience Score percentage (0-100).
|
|
|
141
141
|
Metascore (0-100 scale). Leave empty if not available.
|
|
142
142
|
{% /instructions %}
|
|
143
143
|
|
|
144
|
-
{% /
|
|
144
|
+
{% /group %}
|
|
145
145
|
|
|
146
|
-
{%
|
|
146
|
+
{% group id="summary" title="Summary" %}
|
|
147
147
|
|
|
148
148
|
{% field kind="string" id="logline" label="One-Line Summary" role="agent" maxLength=300 %}{% /field %}
|
|
149
149
|
|
|
@@ -163,6 +163,6 @@ Major awards won.
|
|
|
163
163
|
Example: Oscar | Best Picture | 1995
|
|
164
164
|
{% /instructions %}
|
|
165
165
|
|
|
166
|
-
{% /
|
|
166
|
+
{% /group %}
|
|
167
167
|
|
|
168
168
|
{% /form %}
|
|
@@ -45,7 +45,7 @@ markform:
|
|
|
45
45
|
Comprehensive movie research covering ratings from multiple sources, box office performance, full cast and crew, technical specifications, streaming availability, and cultural impact analysis.
|
|
46
46
|
{% /description %}
|
|
47
47
|
|
|
48
|
-
{%
|
|
48
|
+
{% group id="movie_input" title="Movie Identification" %}
|
|
49
49
|
|
|
50
50
|
{% field kind="string" id="movie" label="Movie" role="user" required=true minLength=1 maxLength=300 %}{% /field %}
|
|
51
51
|
|
|
@@ -53,11 +53,11 @@ Comprehensive movie research covering ratings from multiple sources, box office
|
|
|
53
53
|
Enter the movie title (add any details to help identify, like "Barbie 2023" or "the Batman movie with Robert Pattinson").
|
|
54
54
|
{% /instructions %}
|
|
55
55
|
|
|
56
|
-
{% /
|
|
56
|
+
{% /group %}
|
|
57
57
|
|
|
58
58
|
## Title Identification
|
|
59
59
|
|
|
60
|
-
{%
|
|
60
|
+
{% group id="title_identification" title="Title Identification" %}
|
|
61
61
|
|
|
62
62
|
{% field kind="string" id="full_title" label="Full Title" role="agent" required=true %}{% /field %}
|
|
63
63
|
|
|
@@ -67,11 +67,11 @@ Official title including subtitle if any (e.g., "The Lord of the Rings: The Fell
|
|
|
67
67
|
|
|
68
68
|
{% field kind="number" id="year" label="Release Year" role="agent" required=true min=1888 max=2030 %}{% /field %}
|
|
69
69
|
|
|
70
|
-
{% /
|
|
70
|
+
{% /group %}
|
|
71
71
|
|
|
72
72
|
## Sources
|
|
73
73
|
|
|
74
|
-
{%
|
|
74
|
+
{% group id="primary_sources" title="Primary Sources" %}
|
|
75
75
|
|
|
76
76
|
{% field kind="url" id="imdb_url" label="IMDB URL" role="agent" required=true %}{% /field %}
|
|
77
77
|
|
|
@@ -92,9 +92,9 @@ Direct link to the movie's Rotten Tomatoes page.
|
|
|
92
92
|
Direct link to the movie's Metacritic page.
|
|
93
93
|
{% /instructions %}
|
|
94
94
|
|
|
95
|
-
{% /
|
|
95
|
+
{% /group %}
|
|
96
96
|
|
|
97
|
-
{%
|
|
97
|
+
{% group id="box_office_sources" title="Box Office Sources" %}
|
|
98
98
|
|
|
99
99
|
{% field kind="url" id="boxofficemojo_url" label="Box Office Mojo URL" role="agent" %}{% /field %}
|
|
100
100
|
|
|
@@ -109,9 +109,9 @@ Format: https://www.boxofficemojo.com/title/tt0111161/
|
|
|
109
109
|
Alternative/supplementary box office data and profitability analysis.
|
|
110
110
|
{% /instructions %}
|
|
111
111
|
|
|
112
|
-
{% /
|
|
112
|
+
{% /group %}
|
|
113
113
|
|
|
114
|
-
{%
|
|
114
|
+
{% group id="availability_sources" title="Availability Sources" %}
|
|
115
115
|
|
|
116
116
|
{% field kind="url" id="justwatch_url" label="JustWatch URL" role="agent" %}{% /field %}
|
|
117
117
|
|
|
@@ -120,9 +120,9 @@ Best source for current streaming availability. Use US region.
|
|
|
120
120
|
Format: https://www.justwatch.com/us/movie/the-shawshank-redemption
|
|
121
121
|
{% /instructions %}
|
|
122
122
|
|
|
123
|
-
{% /
|
|
123
|
+
{% /group %}
|
|
124
124
|
|
|
125
|
-
{%
|
|
125
|
+
{% group id="additional_sources" title="Additional Sources" %}
|
|
126
126
|
|
|
127
127
|
{% field kind="url" id="letterboxd_url" label="Letterboxd URL" role="agent" %}{% /field %}
|
|
128
128
|
|
|
@@ -142,11 +142,11 @@ For production history, cultural impact, comprehensive awards list.
|
|
|
142
142
|
Studio or film's official website, if still active.
|
|
143
143
|
{% /instructions %}
|
|
144
144
|
|
|
145
|
-
{% /
|
|
145
|
+
{% /group %}
|
|
146
146
|
|
|
147
147
|
## Basic Details
|
|
148
148
|
|
|
149
|
-
{%
|
|
149
|
+
{% group id="basic_details" title="Basic Details" %}
|
|
150
150
|
|
|
151
151
|
{% field kind="string_list" id="directors" label="Director(s)" role="agent" required=true %}{% /field %}
|
|
152
152
|
|
|
@@ -202,11 +202,11 @@ Select all applicable genres from IMDB (up to 5).
|
|
|
202
202
|
Production countries, one per line.
|
|
203
203
|
{% /instructions %}
|
|
204
204
|
|
|
205
|
-
{% /
|
|
205
|
+
{% /group %}
|
|
206
206
|
|
|
207
207
|
## Cast & Crew
|
|
208
208
|
|
|
209
|
-
{%
|
|
209
|
+
{% group id="cast_crew" title="Cast & Crew" %}
|
|
210
210
|
|
|
211
211
|
{% field kind="table" id="lead_cast" label="Lead Cast" role="agent" minRows=1 maxRows=10
|
|
212
212
|
columnIds=["actor_name", "character_name"]
|
|
@@ -244,11 +244,11 @@ Format: Name (producer type)
|
|
|
244
244
|
Example: "Emma Thomas (producer)"
|
|
245
245
|
{% /instructions %}
|
|
246
246
|
|
|
247
|
-
{% /
|
|
247
|
+
{% /group %}
|
|
248
248
|
|
|
249
249
|
## Ratings
|
|
250
250
|
|
|
251
|
-
{%
|
|
251
|
+
{% group id="imdb_ratings" title="IMDB Ratings" %}
|
|
252
252
|
|
|
253
253
|
{% field kind="number" id="imdb_rating" label="IMDB Rating" role="agent" min=1.0 max=10.0 %}{% /field %}
|
|
254
254
|
|
|
@@ -262,9 +262,9 @@ IMDB user rating (1.0-10.0 scale).
|
|
|
262
262
|
Number of IMDB user votes (e.g., 2800000 for a popular film).
|
|
263
263
|
{% /instructions %}
|
|
264
264
|
|
|
265
|
-
{% /
|
|
265
|
+
{% /group %}
|
|
266
266
|
|
|
267
|
-
{%
|
|
267
|
+
{% group id="rotten_tomatoes_ratings" title="Rotten Tomatoes Ratings" %}
|
|
268
268
|
|
|
269
269
|
{% field kind="number" id="rt_critics_score" label="Tomatometer (Critics)" role="agent" min=0 max=100 %}{% /field %}
|
|
270
270
|
|
|
@@ -286,9 +286,9 @@ Audience Score percentage (0-100).
|
|
|
286
286
|
The official Rotten Tomatoes critics consensus statement, if available.
|
|
287
287
|
{% /instructions %}
|
|
288
288
|
|
|
289
|
-
{% /
|
|
289
|
+
{% /group %}
|
|
290
290
|
|
|
291
|
-
{%
|
|
291
|
+
{% group id="metacritic_ratings" title="Metacritic Ratings" %}
|
|
292
292
|
|
|
293
293
|
{% field kind="number" id="metacritic_score" label="Metacritic Score" role="agent" min=0 max=100 %}{% /field %}
|
|
294
294
|
|
|
@@ -296,9 +296,9 @@ The official Rotten Tomatoes critics consensus statement, if available.
|
|
|
296
296
|
Metascore (0-100 scale). Leave empty if not available.
|
|
297
297
|
{% /instructions %}
|
|
298
298
|
|
|
299
|
-
{% /
|
|
299
|
+
{% /group %}
|
|
300
300
|
|
|
301
|
-
{%
|
|
301
|
+
{% group id="additional_ratings" title="Additional Ratings" %}
|
|
302
302
|
|
|
303
303
|
{% field kind="number" id="letterboxd_rating" label="Letterboxd Rating" role="agent" min=0.5 max=5.0 %}{% /field %}
|
|
304
304
|
|
|
@@ -312,11 +312,11 @@ Letterboxd average rating (0.5-5.0 scale, in 0.1 increments).
|
|
|
312
312
|
Opening weekend audience grade (A+ to F). Only available for theatrical releases.
|
|
313
313
|
{% /instructions %}
|
|
314
314
|
|
|
315
|
-
{% /
|
|
315
|
+
{% /group %}
|
|
316
316
|
|
|
317
317
|
## Box Office
|
|
318
318
|
|
|
319
|
-
{%
|
|
319
|
+
{% group id="box_office" title="Box Office" %}
|
|
320
320
|
|
|
321
321
|
{% field kind="number" id="budget_millions" label="Budget ($M)" role="agent" min=0 %}{% /field %}
|
|
322
322
|
|
|
@@ -342,11 +342,11 @@ Global theatrical gross in millions USD.
|
|
|
342
342
|
US opening weekend gross in millions USD.
|
|
343
343
|
{% /instructions %}
|
|
344
344
|
|
|
345
|
-
{% /
|
|
345
|
+
{% /group %}
|
|
346
346
|
|
|
347
347
|
## Technical Specifications
|
|
348
348
|
|
|
349
|
-
{%
|
|
349
|
+
{% group id="technical_specs" title="Technical Specifications" %}
|
|
350
350
|
|
|
351
351
|
{% field kind="single_select" id="aspect_ratio" label="Aspect Ratio" role="agent" %}
|
|
352
352
|
- [ ] 1.33:1 (Academy) {% #ratio_133 %}
|
|
@@ -381,11 +381,11 @@ Primary sound format (e.g., "Dolby Atmos", "DTS", "Dolby Digital").
|
|
|
381
381
|
Primary camera system used (e.g., "Arri Alexa 65", "IMAX 15-perf", "Panavision Panaflex").
|
|
382
382
|
{% /instructions %}
|
|
383
383
|
|
|
384
|
-
{% /
|
|
384
|
+
{% /group %}
|
|
385
385
|
|
|
386
386
|
## Streaming Availability
|
|
387
387
|
|
|
388
|
-
{%
|
|
388
|
+
{% group id="streaming_availability" title="Streaming Availability (US)" %}
|
|
389
389
|
|
|
390
390
|
{% field kind="multi_select" id="streaming_subscription" label="Streaming (Subscription)" role="agent" %}
|
|
391
391
|
- [ ] Netflix {% #netflix %}
|
|
@@ -414,11 +414,11 @@ Select all platforms where this film is currently available to stream (subscript
|
|
|
414
414
|
- [ ] 4K UHD available {% #uhd_4k %}
|
|
415
415
|
{% /field %}
|
|
416
416
|
|
|
417
|
-
{% /
|
|
417
|
+
{% /group %}
|
|
418
418
|
|
|
419
419
|
## Content & Themes
|
|
420
420
|
|
|
421
|
-
{%
|
|
421
|
+
{% group id="content_themes" title="Content & Themes" %}
|
|
422
422
|
|
|
423
423
|
{% field kind="checkboxes" id="content_warnings" label="Content Warnings" role="agent" checkboxMode="simple" %}
|
|
424
424
|
- [ ] Intense violence {% #violence %}
|
|
@@ -441,11 +441,11 @@ Check any content warnings that apply. Use IMDB Parents Guide as reference.
|
|
|
441
441
|
Major themes explored in the film (e.g., "redemption", "family", "identity", "war").
|
|
442
442
|
{% /instructions %}
|
|
443
443
|
|
|
444
|
-
{% /
|
|
444
|
+
{% /group %}
|
|
445
445
|
|
|
446
446
|
## Summary & Legacy
|
|
447
447
|
|
|
448
|
-
{%
|
|
448
|
+
{% group id="summary" title="Summary" %}
|
|
449
449
|
|
|
450
450
|
{% field kind="string" id="logline" label="One-Line Summary" role="agent" maxLength=300 %}{% /field %}
|
|
451
451
|
|
|
@@ -476,9 +476,9 @@ Example: Oscar | Best Picture | 1995
|
|
|
476
476
|
2-3 memorable critic quotes that capture reception.
|
|
477
477
|
{% /instructions %}
|
|
478
478
|
|
|
479
|
-
{% /
|
|
479
|
+
{% /group %}
|
|
480
480
|
|
|
481
|
-
{%
|
|
481
|
+
{% group id="cultural_legacy" title="Cultural Legacy" %}
|
|
482
482
|
|
|
483
483
|
{% field kind="string" id="cultural_impact" label="Cultural Impact" role="agent" maxLength=500 %}{% /field %}
|
|
484
484
|
|
|
@@ -493,6 +493,6 @@ Leave empty for recent releases without established legacy.
|
|
|
493
493
|
Films with similar themes, style, or appeal. One per line.
|
|
494
494
|
{% /instructions %}
|
|
495
495
|
|
|
496
|
-
{% /
|
|
496
|
+
{% /group %}
|
|
497
497
|
|
|
498
498
|
{% /form %}
|
|
@@ -16,18 +16,18 @@ markform:
|
|
|
16
16
|
|
|
17
17
|
## Movie Research Example
|
|
18
18
|
|
|
19
|
-
{%
|
|
19
|
+
{% group id="movie_input" title="Movie Identification" %}
|
|
20
20
|
|
|
21
21
|
What movie do you want to research? \[*This field is filled in by the user (`role="user"`).*\]
|
|
22
22
|
|
|
23
23
|
{% field kind="string" id="movie" label="Movie" role="user" required=true minLength=1 maxLength=300 %}{% /field %}
|
|
24
24
|
{% instructions ref="movie" %}Enter the movie title (add year or details for disambiguation).{% /instructions %}
|
|
25
25
|
|
|
26
|
-
{% /
|
|
26
|
+
{% /group %}
|
|
27
27
|
|
|
28
28
|
## About the Movie
|
|
29
29
|
|
|
30
|
-
{%
|
|
30
|
+
{% group id="about_the_movie" title="About the Movie" %}
|
|
31
31
|
|
|
32
32
|
**Title:**
|
|
33
33
|
|
|
@@ -63,6 +63,6 @@ What movie do you want to research? \[*This field is filled in by the user (`rol
|
|
|
63
63
|
{% field kind="string" id="logline" label="One-Line Summary" role="agent" maxLength=300 %}{% /field %}
|
|
64
64
|
{% instructions ref="logline" %}Brief plot summary in 1-2 sentences, no spoilers.{% /instructions %}
|
|
65
65
|
|
|
66
|
-
{% /
|
|
66
|
+
{% /group %}
|
|
67
67
|
|
|
68
68
|
{% /form %}
|