markform 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +664 -0
- package/README.md +216 -44
- package/dist/ai-sdk.d.mts +2 -3
- package/dist/ai-sdk.mjs +2 -3
- package/dist/{apply-C0vjijlP.mjs → apply-BQdd-fdx.mjs} +381 -38
- package/dist/bin.d.mts +0 -0
- package/dist/bin.mjs +4 -5
- package/dist/{cli-9fvFySww.mjs → cli-pjOiHgCW.mjs} +506 -94
- package/dist/cli.d.mts +1 -2
- package/dist/cli.mjs +3 -3
- package/dist/{coreTypes-T7dAuewt.d.mts → coreTypes--6etkcwb.d.mts} +1088 -131
- package/dist/index.d.mts +90 -10
- package/dist/index.mjs +2 -2
- package/dist/{src-DBD3Dt4f.mjs → src-Cs4_9lWP.mjs} +461 -96
- package/examples/simple/simple-mock-filled.form.md +36 -0
- package/examples/simple/simple-skipped-filled.form.md +147 -0
- package/examples/simple/simple-with-skips.session.yaml +230 -0
- package/examples/simple/simple.form.md +22 -0
- package/examples/simple/simple.session.yaml +60 -28
- package/examples/startup-deep-research/startup-deep-research.form.md +404 -0
- package/examples/startup-research/startup-research-mock-filled.form.md +307 -0
- package/examples/startup-research/startup-research.form.md +211 -0
- package/package.json +17 -16
- package/dist/ai-sdk.mjs.map +0 -1
- package/dist/apply-C0vjijlP.mjs.map +0 -1
- package/dist/bin.mjs.map +0 -1
- package/dist/cli-9fvFySww.mjs.map +0 -1
- package/dist/src-DBD3Dt4f.mjs.map +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as getWebSearchConfig, _ as DEFAULT_PRIORITY, at as SessionTranscriptSchema, et as PatchSchema, f as AGENT_ROLE, h as DEFAULT_MAX_TURNS, m as DEFAULT_MAX_PATCHES_PER_TURN, n as getFieldsForRoles, p as DEFAULT_MAX_ISSUES, r as inspect, t as applyPatches, u as serialize, v as DEFAULT_ROLE_INSTRUCTIONS } from "./apply-BQdd-fdx.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import Markdoc from "@markdoc/markdoc";
|
|
4
4
|
import YAML from "yaml";
|
|
5
|
-
import {
|
|
5
|
+
import { sha256 } from "js-sha256";
|
|
6
6
|
import { generateText, stepCountIs, zodSchema } from "ai";
|
|
7
|
+
import { openai } from "@ai-sdk/openai";
|
|
8
|
+
import { google } from "@ai-sdk/google";
|
|
7
9
|
|
|
8
10
|
//#region src/engine/parse.ts
|
|
9
11
|
/**
|
|
@@ -395,11 +397,17 @@ function parseCheckboxesField(node) {
|
|
|
395
397
|
const approvalModeStr = getStringAttr(node, "approvalMode");
|
|
396
398
|
let approvalMode = "none";
|
|
397
399
|
if (approvalModeStr === "blocking") approvalMode = "blocking";
|
|
400
|
+
const explicitRequired = getBooleanAttr(node, "required");
|
|
401
|
+
let required;
|
|
402
|
+
if (checkboxMode === "explicit") {
|
|
403
|
+
if (explicitRequired === false) throw new ParseError(`Checkbox field "${label}" has checkboxMode="explicit" which is inherently required. Cannot set required=false. Remove required attribute or change checkboxMode.`);
|
|
404
|
+
required = true;
|
|
405
|
+
} else required = explicitRequired ?? false;
|
|
398
406
|
const field = {
|
|
399
407
|
kind: "checkboxes",
|
|
400
408
|
id,
|
|
401
409
|
label,
|
|
402
|
-
required
|
|
410
|
+
required,
|
|
403
411
|
priority: getPriorityAttr(node),
|
|
404
412
|
role: getStringAttr(node, "role") ?? AGENT_ROLE,
|
|
405
413
|
checkboxMode,
|
|
@@ -423,6 +431,69 @@ function parseCheckboxesField(node) {
|
|
|
423
431
|
};
|
|
424
432
|
}
|
|
425
433
|
/**
|
|
434
|
+
* Parse a url-field tag.
|
|
435
|
+
*/
|
|
436
|
+
function parseUrlField(node) {
|
|
437
|
+
const id = getStringAttr(node, "id");
|
|
438
|
+
const label = getStringAttr(node, "label");
|
|
439
|
+
if (!id) throw new ParseError("url-field missing required 'id' attribute");
|
|
440
|
+
if (!label) throw new ParseError(`url-field '${id}' missing required 'label' attribute`);
|
|
441
|
+
const field = {
|
|
442
|
+
kind: "url",
|
|
443
|
+
id,
|
|
444
|
+
label,
|
|
445
|
+
required: getBooleanAttr(node, "required") ?? false,
|
|
446
|
+
priority: getPriorityAttr(node),
|
|
447
|
+
role: getStringAttr(node, "role") ?? AGENT_ROLE,
|
|
448
|
+
validate: getValidateAttr(node)
|
|
449
|
+
};
|
|
450
|
+
const fenceContent = extractFenceValue(node);
|
|
451
|
+
return {
|
|
452
|
+
field,
|
|
453
|
+
value: {
|
|
454
|
+
kind: "url",
|
|
455
|
+
value: fenceContent !== null ? fenceContent.trim() : null
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Parse a url-list tag.
|
|
461
|
+
*/
|
|
462
|
+
function parseUrlListField(node) {
|
|
463
|
+
const id = getStringAttr(node, "id");
|
|
464
|
+
const label = getStringAttr(node, "label");
|
|
465
|
+
if (!id) throw new ParseError("url-list missing required 'id' attribute");
|
|
466
|
+
if (!label) throw new ParseError(`url-list '${id}' missing required 'label' attribute`);
|
|
467
|
+
const field = {
|
|
468
|
+
kind: "url_list",
|
|
469
|
+
id,
|
|
470
|
+
label,
|
|
471
|
+
required: getBooleanAttr(node, "required") ?? false,
|
|
472
|
+
priority: getPriorityAttr(node),
|
|
473
|
+
role: getStringAttr(node, "role") ?? AGENT_ROLE,
|
|
474
|
+
minItems: getNumberAttr(node, "minItems"),
|
|
475
|
+
maxItems: getNumberAttr(node, "maxItems"),
|
|
476
|
+
uniqueItems: getBooleanAttr(node, "uniqueItems"),
|
|
477
|
+
validate: getValidateAttr(node)
|
|
478
|
+
};
|
|
479
|
+
const fenceContent = extractFenceValue(node);
|
|
480
|
+
const items = [];
|
|
481
|
+
if (fenceContent !== null) {
|
|
482
|
+
const lines = fenceContent.split("\n");
|
|
483
|
+
for (const line of lines) {
|
|
484
|
+
const trimmed = line.trim();
|
|
485
|
+
if (trimmed) items.push(trimmed);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
field,
|
|
490
|
+
value: {
|
|
491
|
+
kind: "url_list",
|
|
492
|
+
items
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
426
497
|
* Parse a field tag and return field schema and value.
|
|
427
498
|
*/
|
|
428
499
|
function parseField(node) {
|
|
@@ -434,6 +505,8 @@ function parseField(node) {
|
|
|
434
505
|
case "single-select": return parseSingleSelectField(node);
|
|
435
506
|
case "multi-select": return parseMultiSelectField(node);
|
|
436
507
|
case "checkboxes": return parseCheckboxesField(node);
|
|
508
|
+
case "url-field": return parseUrlField(node);
|
|
509
|
+
case "url-list": return parseUrlListField(node);
|
|
437
510
|
default: return null;
|
|
438
511
|
}
|
|
439
512
|
}
|
|
@@ -579,6 +652,7 @@ function parseForm(markdown) {
|
|
|
579
652
|
return {
|
|
580
653
|
schema: formSchema,
|
|
581
654
|
valuesByFieldId,
|
|
655
|
+
skipsByFieldId: {},
|
|
582
656
|
docs,
|
|
583
657
|
orderIndex,
|
|
584
658
|
idIndex
|
|
@@ -960,6 +1034,75 @@ function coerceToCheckboxes(field, rawValue) {
|
|
|
960
1034
|
}
|
|
961
1035
|
};
|
|
962
1036
|
}
|
|
1037
|
+
function coerceToUrl(fieldId, rawValue) {
|
|
1038
|
+
if (rawValue === null) return {
|
|
1039
|
+
ok: true,
|
|
1040
|
+
patch: {
|
|
1041
|
+
op: "set_url",
|
|
1042
|
+
fieldId,
|
|
1043
|
+
value: null
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
if (typeof rawValue === "string") return {
|
|
1047
|
+
ok: true,
|
|
1048
|
+
patch: {
|
|
1049
|
+
op: "set_url",
|
|
1050
|
+
fieldId,
|
|
1051
|
+
value: rawValue
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
return {
|
|
1055
|
+
ok: false,
|
|
1056
|
+
error: `Cannot coerce ${typeof rawValue} to url for field '${fieldId}'`
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
function coerceToUrlList(fieldId, rawValue) {
|
|
1060
|
+
if (rawValue === null) return {
|
|
1061
|
+
ok: true,
|
|
1062
|
+
patch: {
|
|
1063
|
+
op: "set_url_list",
|
|
1064
|
+
fieldId,
|
|
1065
|
+
items: []
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
if (isStringArray(rawValue)) return {
|
|
1069
|
+
ok: true,
|
|
1070
|
+
patch: {
|
|
1071
|
+
op: "set_url_list",
|
|
1072
|
+
fieldId,
|
|
1073
|
+
items: rawValue
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
if (typeof rawValue === "string") return {
|
|
1077
|
+
ok: true,
|
|
1078
|
+
patch: {
|
|
1079
|
+
op: "set_url_list",
|
|
1080
|
+
fieldId,
|
|
1081
|
+
items: [rawValue]
|
|
1082
|
+
},
|
|
1083
|
+
warning: `Coerced single string to array for field '${fieldId}'`
|
|
1084
|
+
};
|
|
1085
|
+
if (Array.isArray(rawValue)) {
|
|
1086
|
+
const items = [];
|
|
1087
|
+
for (const item of rawValue) if (typeof item === "string") items.push(item);
|
|
1088
|
+
else return {
|
|
1089
|
+
ok: false,
|
|
1090
|
+
error: `Cannot coerce array with non-string items to url_list for field '${fieldId}'`
|
|
1091
|
+
};
|
|
1092
|
+
return {
|
|
1093
|
+
ok: true,
|
|
1094
|
+
patch: {
|
|
1095
|
+
op: "set_url_list",
|
|
1096
|
+
fieldId,
|
|
1097
|
+
items
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
return {
|
|
1102
|
+
ok: false,
|
|
1103
|
+
error: `Cannot coerce ${typeof rawValue} to url_list for field '${fieldId}'`
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
963
1106
|
/**
|
|
964
1107
|
* Coerce a raw value to a Patch for a specific field.
|
|
965
1108
|
*/
|
|
@@ -976,10 +1119,8 @@ function coerceToFieldPatch(form, fieldId, rawValue) {
|
|
|
976
1119
|
case "single_select": return coerceToSingleSelect(field, rawValue);
|
|
977
1120
|
case "multi_select": return coerceToMultiSelect(field, rawValue);
|
|
978
1121
|
case "checkboxes": return coerceToCheckboxes(field, rawValue);
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
error: `Unknown field kind: ${field.kind}`
|
|
982
|
-
};
|
|
1122
|
+
case "url": return coerceToUrl(fieldId, rawValue);
|
|
1123
|
+
case "url_list": return coerceToUrlList(fieldId, rawValue);
|
|
983
1124
|
}
|
|
984
1125
|
}
|
|
985
1126
|
/**
|
|
@@ -1062,9 +1203,18 @@ var FormHarness = class {
|
|
|
1062
1203
|
}
|
|
1063
1204
|
/**
|
|
1064
1205
|
* Check if the harness has reached max turns.
|
|
1206
|
+
*
|
|
1207
|
+
* Returns true when we've completed all allowed turns. This happens when:
|
|
1208
|
+
* - turnNumber >= maxTurns AND we've already applied (state is "complete")
|
|
1209
|
+
* - OR turnNumber > maxTurns (we've exceeded the limit)
|
|
1210
|
+
*
|
|
1211
|
+
* This allows the harness loop to run N times when maxTurns=N by returning
|
|
1212
|
+
* false when we're at turn N but haven't applied yet (state is "wait").
|
|
1065
1213
|
*/
|
|
1066
1214
|
hasReachedMaxTurns() {
|
|
1067
|
-
|
|
1215
|
+
if (this.turnNumber > this.config.maxTurns) return true;
|
|
1216
|
+
if (this.turnNumber === this.config.maxTurns && this.state === "complete") return true;
|
|
1217
|
+
return false;
|
|
1068
1218
|
}
|
|
1069
1219
|
/**
|
|
1070
1220
|
* Perform a step - inspect the form and return current state.
|
|
@@ -1093,18 +1243,9 @@ var FormHarness = class {
|
|
|
1093
1243
|
}
|
|
1094
1244
|
this.state = "step";
|
|
1095
1245
|
const result = inspect(this.form, { targetRoles: this.config.targetRoles });
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
else this.state = "wait";
|
|
1100
|
-
return {
|
|
1101
|
-
structureSummary: result.structureSummary,
|
|
1102
|
-
progressSummary: result.progressSummary,
|
|
1103
|
-
issues: limitedIssues,
|
|
1104
|
-
stepBudget,
|
|
1105
|
-
isComplete: result.isComplete,
|
|
1106
|
-
turnNumber: this.turnNumber
|
|
1107
|
-
};
|
|
1246
|
+
const stepResult = this.computeStepResult(result);
|
|
1247
|
+
this.state = stepResult.issues.length === 0 ? "complete" : "wait";
|
|
1248
|
+
return stepResult;
|
|
1108
1249
|
}
|
|
1109
1250
|
/**
|
|
1110
1251
|
* Apply patches to the form.
|
|
@@ -1114,29 +1255,27 @@ var FormHarness = class {
|
|
|
1114
1255
|
*
|
|
1115
1256
|
* @param patches - Patches to apply
|
|
1116
1257
|
* @param issues - Issues that were shown to the agent (for recording)
|
|
1258
|
+
* @param llmStats - Optional LLM stats for session logging
|
|
1117
1259
|
* @returns StepResult after applying patches
|
|
1118
1260
|
*/
|
|
1119
|
-
apply(patches, issues) {
|
|
1261
|
+
apply(patches, issues, llmStats) {
|
|
1120
1262
|
if (this.state !== "wait") throw new Error(`Cannot apply in state: ${this.state}`);
|
|
1121
1263
|
if (patches.length > this.config.maxPatchesPerTurn) throw new Error(`Too many patches: ${patches.length} > ${this.config.maxPatchesPerTurn}`);
|
|
1122
|
-
|
|
1123
|
-
const
|
|
1124
|
-
const
|
|
1125
|
-
|
|
1126
|
-
this.
|
|
1127
|
-
turn: this.turnNumber,
|
|
1128
|
-
inspect: { issues },
|
|
1129
|
-
apply: { patches },
|
|
1130
|
-
after: {
|
|
1131
|
-
requiredIssueCount,
|
|
1132
|
-
markdownSha256: hash
|
|
1133
|
-
}
|
|
1134
|
-
});
|
|
1135
|
-
const limitedIssues = this.filterIssuesByScope(result.issues).slice(0, this.config.maxIssues);
|
|
1136
|
-
const stepBudget = Math.min(this.config.maxPatchesPerTurn, limitedIssues.filter((i) => i.severity === "required").length);
|
|
1137
|
-
if (result.isComplete) this.state = "complete";
|
|
1138
|
-
else if (this.turnNumber >= this.config.maxTurns) this.state = "complete";
|
|
1264
|
+
applyPatches(this.form, patches);
|
|
1265
|
+
const result = inspect(this.form, { targetRoles: this.config.targetRoles });
|
|
1266
|
+
const stepResult = this.computeStepResult(result);
|
|
1267
|
+
this.recordTurn(issues, patches, result, llmStats);
|
|
1268
|
+
if (stepResult.issues.length === 0 || this.turnNumber >= this.config.maxTurns) this.state = "complete";
|
|
1139
1269
|
else this.state = "wait";
|
|
1270
|
+
return stepResult;
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Compute step result from inspect result.
|
|
1274
|
+
* Applies issue filtering and computes step budget.
|
|
1275
|
+
*/
|
|
1276
|
+
computeStepResult(result) {
|
|
1277
|
+
const limitedIssues = this.filterIssuesByScope(result.issues).slice(0, this.config.maxIssues);
|
|
1278
|
+
const stepBudget = Math.min(this.config.maxPatchesPerTurn, limitedIssues.length);
|
|
1140
1279
|
return {
|
|
1141
1280
|
structureSummary: result.structureSummary,
|
|
1142
1281
|
progressSummary: result.progressSummary,
|
|
@@ -1147,6 +1286,26 @@ var FormHarness = class {
|
|
|
1147
1286
|
};
|
|
1148
1287
|
}
|
|
1149
1288
|
/**
|
|
1289
|
+
* Record a turn in the session transcript.
|
|
1290
|
+
*/
|
|
1291
|
+
recordTurn(issues, patches, result, llmStats) {
|
|
1292
|
+
const hash = sha256(serialize(this.form));
|
|
1293
|
+
const requiredIssueCount = result.issues.filter((i) => i.severity === "required").length;
|
|
1294
|
+
const turn = {
|
|
1295
|
+
turn: this.turnNumber,
|
|
1296
|
+
inspect: { issues },
|
|
1297
|
+
apply: { patches },
|
|
1298
|
+
after: {
|
|
1299
|
+
requiredIssueCount,
|
|
1300
|
+
markdownSha256: hash,
|
|
1301
|
+
answeredFieldCount: result.progressSummary.counts.answeredFields,
|
|
1302
|
+
skippedFieldCount: result.progressSummary.counts.skippedFields
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
if (llmStats) turn.llm = llmStats;
|
|
1306
|
+
this.turns.push(turn);
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1150
1309
|
* Check if the form is complete.
|
|
1151
1310
|
*/
|
|
1152
1311
|
isComplete() {
|
|
@@ -1162,8 +1321,7 @@ var FormHarness = class {
|
|
|
1162
1321
|
* Get the SHA256 hash of the current form markdown.
|
|
1163
1322
|
*/
|
|
1164
1323
|
getMarkdownHash() {
|
|
1165
|
-
|
|
1166
|
-
return createHash("sha256").update(markdown).digest("hex");
|
|
1324
|
+
return sha256(serialize(this.form));
|
|
1167
1325
|
}
|
|
1168
1326
|
/**
|
|
1169
1327
|
* Filter issues based on maxFieldsPerTurn and maxGroupsPerTurn limits.
|
|
@@ -1266,7 +1424,9 @@ var MockAgent = class {
|
|
|
1266
1424
|
* Generate patches from the completed mock to address issues.
|
|
1267
1425
|
*
|
|
1268
1426
|
* Processes issues in priority order, generating patches for
|
|
1269
|
-
* fields that have values in the completed mock.
|
|
1427
|
+
* fields that have values in the completed mock. For fields with no
|
|
1428
|
+
* value (empty optional fields), generates skip_field patches.
|
|
1429
|
+
* Returns AgentResponse with patches but no stats (mock doesn't track LLM usage).
|
|
1270
1430
|
*/
|
|
1271
1431
|
async generatePatches(issues, _form, maxPatches) {
|
|
1272
1432
|
const patches = [];
|
|
@@ -1276,17 +1436,43 @@ var MockAgent = class {
|
|
|
1276
1436
|
if (issue.scope !== "field") continue;
|
|
1277
1437
|
const fieldId = issue.ref;
|
|
1278
1438
|
if (addressedFields.has(fieldId)) continue;
|
|
1279
|
-
const completedValue = this.completedValues[fieldId];
|
|
1280
|
-
if (!completedValue) continue;
|
|
1281
1439
|
const field = this.fieldMap.get(fieldId);
|
|
1282
1440
|
if (!field) continue;
|
|
1441
|
+
const completedValue = this.completedValues[fieldId];
|
|
1442
|
+
if (!completedValue || !this.hasValue(completedValue)) {
|
|
1443
|
+
if (!field.required) {
|
|
1444
|
+
patches.push({
|
|
1445
|
+
op: "skip_field",
|
|
1446
|
+
fieldId,
|
|
1447
|
+
reason: "No value in mock form"
|
|
1448
|
+
});
|
|
1449
|
+
addressedFields.add(fieldId);
|
|
1450
|
+
}
|
|
1451
|
+
continue;
|
|
1452
|
+
}
|
|
1283
1453
|
const patch = this.createPatch(fieldId, field, completedValue);
|
|
1284
1454
|
if (patch) {
|
|
1285
1455
|
patches.push(patch);
|
|
1286
1456
|
addressedFields.add(fieldId);
|
|
1287
1457
|
}
|
|
1288
1458
|
}
|
|
1289
|
-
return Promise.resolve(patches);
|
|
1459
|
+
return Promise.resolve({ patches });
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Check if a field value actually has content (not null/empty).
|
|
1463
|
+
*/
|
|
1464
|
+
hasValue(value) {
|
|
1465
|
+
switch (value.kind) {
|
|
1466
|
+
case "string": return value.value !== null && value.value !== "";
|
|
1467
|
+
case "number": return value.value !== null;
|
|
1468
|
+
case "string_list": return value.items.length > 0;
|
|
1469
|
+
case "single_select": return value.selected !== null;
|
|
1470
|
+
case "multi_select": return value.selected.length > 0;
|
|
1471
|
+
case "checkboxes": return true;
|
|
1472
|
+
case "url": return value.value !== null && value.value !== "";
|
|
1473
|
+
case "url_list": return value.items.length > 0;
|
|
1474
|
+
default: return false;
|
|
1475
|
+
}
|
|
1290
1476
|
}
|
|
1291
1477
|
/**
|
|
1292
1478
|
* Create a patch for a field based on its kind and completed value.
|
|
@@ -1323,6 +1509,16 @@ var MockAgent = class {
|
|
|
1323
1509
|
fieldId,
|
|
1324
1510
|
values: value.values
|
|
1325
1511
|
};
|
|
1512
|
+
case "url": return {
|
|
1513
|
+
op: "set_url",
|
|
1514
|
+
fieldId,
|
|
1515
|
+
value: value.value
|
|
1516
|
+
};
|
|
1517
|
+
case "url_list": return {
|
|
1518
|
+
op: "set_url_list",
|
|
1519
|
+
fieldId,
|
|
1520
|
+
items: value.items
|
|
1521
|
+
};
|
|
1326
1522
|
default: return null;
|
|
1327
1523
|
}
|
|
1328
1524
|
}
|
|
@@ -1337,6 +1533,104 @@ function createMockAgent(completedForm) {
|
|
|
1337
1533
|
return new MockAgent(completedForm);
|
|
1338
1534
|
}
|
|
1339
1535
|
|
|
1536
|
+
//#endregion
|
|
1537
|
+
//#region src/harness/prompts.ts
|
|
1538
|
+
/**
|
|
1539
|
+
* Agent Prompts - Centralized prompt definitions for the live agent.
|
|
1540
|
+
*
|
|
1541
|
+
* All hardcoded prompts are defined here for easy review, modification,
|
|
1542
|
+
* and future configurability. This file serves as the single source of
|
|
1543
|
+
* truth for agent behavior instructions.
|
|
1544
|
+
*/
|
|
1545
|
+
/**
|
|
1546
|
+
* Default system prompt for the live agent.
|
|
1547
|
+
*
|
|
1548
|
+
* This is the base instruction set that defines the agent's core behavior
|
|
1549
|
+
* for form filling. It emphasizes accuracy over completeness and prohibits
|
|
1550
|
+
* fabrication of data.
|
|
1551
|
+
*/
|
|
1552
|
+
const DEFAULT_SYSTEM_PROMPT = `# Form Instructions
|
|
1553
|
+
Carefully research answers to all questions in the form, using all available tools you have.
|
|
1554
|
+
|
|
1555
|
+
Guidelines:
|
|
1556
|
+
1. Focus on required fields first (severity: "required"), then address optional fields (severity: "recommended")
|
|
1557
|
+
2. You MUST address ALL issues shown to you - both required AND recommended (optional)
|
|
1558
|
+
3. NEVER fabricate or guess information - only use data you can verify
|
|
1559
|
+
4. If you cannot find verifiable information for a field, use skip_field to mark it as skipped with a reason
|
|
1560
|
+
5. For string fields: use appropriate text from verified sources
|
|
1561
|
+
6. For number fields: use appropriate numeric values from verified sources
|
|
1562
|
+
7. For single_select: choose one valid option ID
|
|
1563
|
+
8. For multi_select: choose one or more valid option IDs
|
|
1564
|
+
9. For checkboxes: set appropriate states (done/todo for simple, yes/no for explicit)
|
|
1565
|
+
|
|
1566
|
+
CRITICAL: Accuracy is more important than completeness. Use skip_field when information cannot be verified.
|
|
1567
|
+
|
|
1568
|
+
Always use the generatePatches tool to submit your field values.
|
|
1569
|
+
`;
|
|
1570
|
+
/**
|
|
1571
|
+
* Web search instructions appended when web search tools are available.
|
|
1572
|
+
*
|
|
1573
|
+
* These instructions enforce that the agent must verify all information
|
|
1574
|
+
* through web search before filling fields.
|
|
1575
|
+
*/
|
|
1576
|
+
const WEB_SEARCH_INSTRUCTIONS = `# Web Search
|
|
1577
|
+
You have access to web search tools. You MUST use them to verify ALL information before filling fields.
|
|
1578
|
+
|
|
1579
|
+
Guidelines:
|
|
1580
|
+
1. Search for official sources (company websites, Crunchbase, LinkedIn, press releases)
|
|
1581
|
+
2. Cross-reference information across multiple sources when possible
|
|
1582
|
+
3. Only fill fields with data you found and verified through search
|
|
1583
|
+
4. If a search returns no results or uncertain information, use skip_field with a reason explaining what you searched for
|
|
1584
|
+
5. NEVER fill fields with guessed or assumed information
|
|
1585
|
+
`;
|
|
1586
|
+
/**
|
|
1587
|
+
* Description for the generatePatches tool.
|
|
1588
|
+
*
|
|
1589
|
+
* This tells the model how to use the patch submission tool.
|
|
1590
|
+
*/
|
|
1591
|
+
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.";
|
|
1592
|
+
/**
|
|
1593
|
+
* Header for the issues section in the context prompt.
|
|
1594
|
+
*/
|
|
1595
|
+
const ISSUES_HEADER = "# Current Form Issues";
|
|
1596
|
+
/**
|
|
1597
|
+
* Template for the issues intro text.
|
|
1598
|
+
* @param maxPatches - Maximum number of patches to generate
|
|
1599
|
+
*/
|
|
1600
|
+
function getIssuesIntro(maxPatches) {
|
|
1601
|
+
return `You need to address up to ${maxPatches} issues. Here are the current issues:`;
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Instructions section for the context prompt.
|
|
1605
|
+
*
|
|
1606
|
+
* This explains the patch format for each field type.
|
|
1607
|
+
*/
|
|
1608
|
+
const PATCH_FORMAT_INSTRUCTIONS = `# Instructions
|
|
1609
|
+
|
|
1610
|
+
Use the generatePatches tool to submit patches for the fields above.
|
|
1611
|
+
Each patch should match the field type:
|
|
1612
|
+
- string: { op: "set_string", fieldId: "...", value: "..." }
|
|
1613
|
+
- number: { op: "set_number", fieldId: "...", value: 123 }
|
|
1614
|
+
- string_list: { op: "set_string_list", fieldId: "...", items: ["...", "..."] }
|
|
1615
|
+
- single_select: { op: "set_single_select", fieldId: "...", selected: "option_id" }
|
|
1616
|
+
- multi_select: { op: "set_multi_select", fieldId: "...", selected: ["opt1", "opt2"] }
|
|
1617
|
+
- checkboxes: { op: "set_checkboxes", fieldId: "...", values: { "opt1": "done", "opt2": "todo" } }
|
|
1618
|
+
- url: { op: "set_url", fieldId: "...", value: "https://..." }
|
|
1619
|
+
- url_list: { op: "set_url_list", fieldId: "...", items: ["https://...", "https://..."] }
|
|
1620
|
+
|
|
1621
|
+
If you cannot find verifiable information for a field, skip it:
|
|
1622
|
+
- skip: { op: "skip_field", fieldId: "...", reason: "Information not available" }`;
|
|
1623
|
+
/**
|
|
1624
|
+
* Section headers used when building the composed system prompt.
|
|
1625
|
+
*/
|
|
1626
|
+
const SECTION_HEADERS = {
|
|
1627
|
+
formInstructions: "# Form Instructions",
|
|
1628
|
+
roleInstructions: (role) => `# Instructions for ${role} role`,
|
|
1629
|
+
roleGuidance: "# Role guidance",
|
|
1630
|
+
fieldInstructions: "# Field-specific instructions",
|
|
1631
|
+
additionalContext: "# Additional Context"
|
|
1632
|
+
};
|
|
1633
|
+
|
|
1340
1634
|
//#endregion
|
|
1341
1635
|
//#region src/harness/liveAgent.ts
|
|
1342
1636
|
/**
|
|
@@ -1347,58 +1641,93 @@ var LiveAgent = class {
|
|
|
1347
1641
|
maxStepsPerTurn;
|
|
1348
1642
|
systemPromptAddition;
|
|
1349
1643
|
targetRole;
|
|
1644
|
+
provider;
|
|
1645
|
+
enableWebSearch;
|
|
1646
|
+
webSearchTools = null;
|
|
1350
1647
|
constructor(config) {
|
|
1351
1648
|
this.model = config.model;
|
|
1352
1649
|
this.maxStepsPerTurn = config.maxStepsPerTurn ?? 3;
|
|
1353
1650
|
this.systemPromptAddition = config.systemPromptAddition;
|
|
1354
1651
|
this.targetRole = config.targetRole ?? AGENT_ROLE;
|
|
1652
|
+
this.provider = config.provider;
|
|
1653
|
+
this.enableWebSearch = config.enableWebSearch ?? true;
|
|
1654
|
+
if (this.enableWebSearch && this.provider) this.webSearchTools = loadWebSearchTools(this.provider);
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Get list of available tool names for this agent.
|
|
1658
|
+
* Useful for logging what capabilities the agent has.
|
|
1659
|
+
*/
|
|
1660
|
+
getAvailableToolNames() {
|
|
1661
|
+
const tools = ["generatePatches"];
|
|
1662
|
+
if (this.webSearchTools) tools.push(...Object.keys(this.webSearchTools));
|
|
1663
|
+
return tools;
|
|
1355
1664
|
}
|
|
1356
1665
|
/**
|
|
1357
1666
|
* Generate patches using the LLM.
|
|
1358
1667
|
*
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1668
|
+
* Each call is stateless - the full form context is provided fresh each turn.
|
|
1669
|
+
* The form itself carries all state (filled values, remaining issues).
|
|
1670
|
+
* Returns patches and per-turn stats for observability.
|
|
1361
1671
|
*/
|
|
1362
1672
|
async generatePatches(issues, form, maxPatches) {
|
|
1363
1673
|
const contextPrompt = buildContextPrompt(issues, form, maxPatches);
|
|
1364
1674
|
let systemPrompt = buildSystemPrompt(form, this.targetRole, issues);
|
|
1365
1675
|
if (this.systemPromptAddition) systemPrompt += "\n\n# Additional Context\n" + this.systemPromptAddition;
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1676
|
+
if (this.enableWebSearch && this.provider && !this.webSearchTools) this.webSearchTools = loadWebSearchTools(this.provider);
|
|
1677
|
+
if (this.webSearchTools && Object.keys(this.webSearchTools).length > 0) systemPrompt += "\n\n" + WEB_SEARCH_INSTRUCTIONS;
|
|
1678
|
+
const tools = {
|
|
1679
|
+
generatePatches: {
|
|
1680
|
+
description: GENERATE_PATCHES_TOOL_DESCRIPTION,
|
|
1681
|
+
inputSchema: zodSchema(z.object({ patches: z.array(PatchSchema).max(maxPatches).describe("Array of patches. Each patch sets a value for one field.") }))
|
|
1682
|
+
},
|
|
1683
|
+
...this.webSearchTools
|
|
1369
1684
|
};
|
|
1370
1685
|
const result = await generateText({
|
|
1371
1686
|
model: this.model,
|
|
1372
1687
|
system: systemPrompt,
|
|
1373
1688
|
prompt: contextPrompt,
|
|
1374
|
-
tools
|
|
1689
|
+
tools,
|
|
1375
1690
|
stopWhen: stepCountIs(this.maxStepsPerTurn)
|
|
1376
1691
|
});
|
|
1377
1692
|
const patches = [];
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1693
|
+
const toolCallCounts = /* @__PURE__ */ new Map();
|
|
1694
|
+
for (const step of result.steps) for (const toolCall of step.toolCalls) {
|
|
1695
|
+
const count = toolCallCounts.get(toolCall.toolName) ?? 0;
|
|
1696
|
+
toolCallCounts.set(toolCall.toolName, count + 1);
|
|
1697
|
+
if (toolCall.toolName === "generatePatches" && "input" in toolCall) {
|
|
1698
|
+
const input = toolCall.input;
|
|
1699
|
+
patches.push(...input.patches);
|
|
1700
|
+
}
|
|
1381
1701
|
}
|
|
1382
|
-
|
|
1702
|
+
const toolCalls = [];
|
|
1703
|
+
for (const [name, count] of toolCallCounts) toolCalls.push({
|
|
1704
|
+
name,
|
|
1705
|
+
count
|
|
1706
|
+
});
|
|
1707
|
+
const requiredRemaining = issues.filter((i) => i.severity === "required").length;
|
|
1708
|
+
const optionalRemaining = issues.filter((i) => i.severity === "recommended").length;
|
|
1709
|
+
const stats = {
|
|
1710
|
+
inputTokens: result.usage?.inputTokens,
|
|
1711
|
+
outputTokens: result.usage?.outputTokens,
|
|
1712
|
+
toolCalls,
|
|
1713
|
+
formProgress: {
|
|
1714
|
+
answeredFields: Object.keys(form.valuesByFieldId).filter((id) => form.valuesByFieldId[id] !== null).length,
|
|
1715
|
+
skippedFields: Object.keys(form.skipsByFieldId ?? {}).filter((id) => form.skipsByFieldId?.[id]?.skipped).length,
|
|
1716
|
+
requiredRemaining,
|
|
1717
|
+
optionalRemaining
|
|
1718
|
+
},
|
|
1719
|
+
prompts: {
|
|
1720
|
+
system: systemPrompt,
|
|
1721
|
+
context: contextPrompt
|
|
1722
|
+
}
|
|
1723
|
+
};
|
|
1724
|
+
return {
|
|
1725
|
+
patches: patches.slice(0, maxPatches),
|
|
1726
|
+
stats
|
|
1727
|
+
};
|
|
1383
1728
|
}
|
|
1384
1729
|
};
|
|
1385
1730
|
/**
|
|
1386
|
-
* Default system prompt for the live agent.
|
|
1387
|
-
*/
|
|
1388
|
-
const DEFAULT_SYSTEM_PROMPT = `You are a form-filling assistant. Your task is to analyze form issues and generate patches to fill in the required fields.
|
|
1389
|
-
|
|
1390
|
-
Guidelines:
|
|
1391
|
-
1. Focus on required fields first (severity: "required")
|
|
1392
|
-
2. Use realistic but generic values when specific data is not provided
|
|
1393
|
-
3. Match the expected field types exactly
|
|
1394
|
-
4. For string fields: use appropriate text
|
|
1395
|
-
5. For number fields: use appropriate numeric values
|
|
1396
|
-
6. For single_select: choose one valid option ID
|
|
1397
|
-
7. For multi_select: choose one or more valid option IDs
|
|
1398
|
-
8. For checkboxes: set appropriate states (done/todo for simple, yes/no for explicit)
|
|
1399
|
-
|
|
1400
|
-
Always use the generatePatches tool to submit your field values.`;
|
|
1401
|
-
/**
|
|
1402
1731
|
* Extract doc blocks of a specific tag type for a given ref.
|
|
1403
1732
|
*/
|
|
1404
1733
|
function getDocBlocks(docs, ref, tag) {
|
|
@@ -1419,19 +1748,19 @@ function buildSystemPrompt(form, targetRole, issues) {
|
|
|
1419
1748
|
const formInstructions = getDocBlocks(form.docs, form.schema.id, "instructions");
|
|
1420
1749
|
if (formInstructions.length > 0) {
|
|
1421
1750
|
sections.push("");
|
|
1422
|
-
sections.push(
|
|
1751
|
+
sections.push(SECTION_HEADERS.formInstructions);
|
|
1423
1752
|
for (const doc of formInstructions) sections.push(doc.bodyMarkdown.trim());
|
|
1424
1753
|
}
|
|
1425
1754
|
const roleInstructions = form.metadata?.roleInstructions?.[targetRole];
|
|
1426
1755
|
if (roleInstructions) {
|
|
1427
1756
|
sections.push("");
|
|
1428
|
-
sections.push(
|
|
1757
|
+
sections.push(SECTION_HEADERS.roleInstructions(targetRole));
|
|
1429
1758
|
sections.push(roleInstructions);
|
|
1430
1759
|
} else {
|
|
1431
1760
|
const defaultRoleInstr = DEFAULT_ROLE_INSTRUCTIONS[targetRole];
|
|
1432
1761
|
if (defaultRoleInstr) {
|
|
1433
1762
|
sections.push("");
|
|
1434
|
-
sections.push(
|
|
1763
|
+
sections.push(SECTION_HEADERS.roleGuidance);
|
|
1435
1764
|
sections.push(defaultRoleInstr);
|
|
1436
1765
|
}
|
|
1437
1766
|
}
|
|
@@ -1443,19 +1772,31 @@ function buildSystemPrompt(form, targetRole, issues) {
|
|
|
1443
1772
|
}
|
|
1444
1773
|
if (fieldInstructions.length > 0) {
|
|
1445
1774
|
sections.push("");
|
|
1446
|
-
sections.push(
|
|
1775
|
+
sections.push(SECTION_HEADERS.fieldInstructions);
|
|
1447
1776
|
sections.push(...fieldInstructions);
|
|
1448
1777
|
}
|
|
1449
1778
|
return sections.join("\n");
|
|
1450
1779
|
}
|
|
1451
1780
|
/**
|
|
1452
|
-
* Build a context prompt with
|
|
1781
|
+
* Build a context prompt with full form state and remaining issues.
|
|
1782
|
+
*
|
|
1783
|
+
* The form markdown shows the agent exactly what's been filled so far,
|
|
1784
|
+
* making each turn stateless - all state is in the form itself.
|
|
1453
1785
|
*/
|
|
1454
1786
|
function buildContextPrompt(issues, form, maxPatches) {
|
|
1455
1787
|
const lines = [];
|
|
1456
|
-
lines.push("# Current Form
|
|
1788
|
+
lines.push("# Current Form State");
|
|
1789
|
+
lines.push("");
|
|
1790
|
+
lines.push("Below is the complete form with all currently filled values.");
|
|
1791
|
+
lines.push("Fields marked with `[ ]` or empty values still need to be filled.");
|
|
1457
1792
|
lines.push("");
|
|
1458
|
-
lines.push(
|
|
1793
|
+
lines.push("```markdown");
|
|
1794
|
+
lines.push(serialize(form));
|
|
1795
|
+
lines.push("```");
|
|
1796
|
+
lines.push("");
|
|
1797
|
+
lines.push(ISSUES_HEADER);
|
|
1798
|
+
lines.push("");
|
|
1799
|
+
lines.push(getIssuesIntro(maxPatches));
|
|
1459
1800
|
lines.push("");
|
|
1460
1801
|
for (const issue of issues) {
|
|
1461
1802
|
lines.push(`- **${issue.ref}** (${issue.scope}): ${issue.message}`);
|
|
@@ -1473,16 +1814,7 @@ function buildContextPrompt(issues, form, maxPatches) {
|
|
|
1473
1814
|
}
|
|
1474
1815
|
lines.push("");
|
|
1475
1816
|
}
|
|
1476
|
-
lines.push(
|
|
1477
|
-
lines.push("");
|
|
1478
|
-
lines.push("Use the generatePatches tool to submit patches for the fields above.");
|
|
1479
|
-
lines.push("Each patch should match the field type:");
|
|
1480
|
-
lines.push("- string: { op: \"set_string\", fieldId: \"...\", value: \"...\" }");
|
|
1481
|
-
lines.push("- number: { op: \"set_number\", fieldId: \"...\", value: 123 }");
|
|
1482
|
-
lines.push("- string_list: { op: \"set_string_list\", fieldId: \"...\", items: [\"...\", \"...\"] }");
|
|
1483
|
-
lines.push("- single_select: { op: \"set_single_select\", fieldId: \"...\", selected: \"option_id\" }");
|
|
1484
|
-
lines.push("- multi_select: { op: \"set_multi_select\", fieldId: \"...\", selected: [\"opt1\", \"opt2\"] }");
|
|
1485
|
-
lines.push("- checkboxes: { op: \"set_checkboxes\", fieldId: \"...\", values: { \"opt1\": \"done\", \"opt2\": \"todo\" } }");
|
|
1817
|
+
lines.push(PATCH_FORMAT_INSTRUCTIONS);
|
|
1486
1818
|
return lines.join("\n");
|
|
1487
1819
|
}
|
|
1488
1820
|
/**
|
|
@@ -1493,6 +1825,26 @@ function findField(form, fieldId) {
|
|
|
1493
1825
|
return null;
|
|
1494
1826
|
}
|
|
1495
1827
|
/**
|
|
1828
|
+
* Load web search tools for a provider.
|
|
1829
|
+
*
|
|
1830
|
+
* Uses statically imported provider modules to get web search tools.
|
|
1831
|
+
* Returns empty object if provider doesn't support web search.
|
|
1832
|
+
*/
|
|
1833
|
+
function loadWebSearchTools(provider) {
|
|
1834
|
+
if (!getWebSearchConfig(provider)) return {};
|
|
1835
|
+
switch (provider) {
|
|
1836
|
+
case "openai":
|
|
1837
|
+
if (openai.tools?.webSearch) return { web_search: openai.tools.webSearch({}) };
|
|
1838
|
+
if (openai.tools?.webSearchPreview) return { web_search: openai.tools.webSearchPreview({}) };
|
|
1839
|
+
return {};
|
|
1840
|
+
case "google":
|
|
1841
|
+
if (google.tools?.googleSearch) return { google_search: google.tools.googleSearch({}) };
|
|
1842
|
+
return {};
|
|
1843
|
+
case "xai": return {};
|
|
1844
|
+
default: return {};
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
/**
|
|
1496
1848
|
* Create a live agent with the given configuration.
|
|
1497
1849
|
*/
|
|
1498
1850
|
function createLiveAgent(config) {
|
|
@@ -1692,6 +2044,7 @@ async function fillForm(options) {
|
|
|
1692
2044
|
groups: []
|
|
1693
2045
|
},
|
|
1694
2046
|
valuesByFieldId: {},
|
|
2047
|
+
skipsByFieldId: {},
|
|
1695
2048
|
docs: [],
|
|
1696
2049
|
orderIndex: [],
|
|
1697
2050
|
idIndex: /* @__PURE__ */ new Map()
|
|
@@ -1701,9 +2054,13 @@ async function fillForm(options) {
|
|
|
1701
2054
|
};
|
|
1702
2055
|
}
|
|
1703
2056
|
let model;
|
|
2057
|
+
let provider;
|
|
1704
2058
|
if (!options._testAgent) try {
|
|
1705
|
-
if (typeof options.model === "string")
|
|
1706
|
-
|
|
2059
|
+
if (typeof options.model === "string") {
|
|
2060
|
+
const resolved = await resolveModel(options.model);
|
|
2061
|
+
model = resolved.model;
|
|
2062
|
+
provider = resolved.provider;
|
|
2063
|
+
} else model = options.model;
|
|
1707
2064
|
} catch (error) {
|
|
1708
2065
|
const message = error instanceof Error ? error.message : String(error);
|
|
1709
2066
|
return buildErrorResult(form, [`Model resolution error: ${message}`], []);
|
|
@@ -1733,7 +2090,9 @@ async function fillForm(options) {
|
|
|
1733
2090
|
const agent = options._testAgent ?? createLiveAgent({
|
|
1734
2091
|
model,
|
|
1735
2092
|
systemPromptAddition: options.systemPromptAddition,
|
|
1736
|
-
targetRole: targetRoles[0] ?? AGENT_ROLE
|
|
2093
|
+
targetRole: targetRoles[0] ?? AGENT_ROLE,
|
|
2094
|
+
provider,
|
|
2095
|
+
enableWebSearch: true
|
|
1737
2096
|
});
|
|
1738
2097
|
let turnCount = 0;
|
|
1739
2098
|
let stepResult = harness.step();
|
|
@@ -1742,12 +2101,18 @@ async function fillForm(options) {
|
|
|
1742
2101
|
ok: false,
|
|
1743
2102
|
reason: "cancelled"
|
|
1744
2103
|
}, inputContextWarnings, stepResult.issues);
|
|
1745
|
-
const patches = await agent.generatePatches(stepResult.issues, form, maxPatchesPerTurn);
|
|
2104
|
+
const { patches, stats } = await agent.generatePatches(stepResult.issues, form, maxPatchesPerTurn);
|
|
1746
2105
|
if (options.signal?.aborted) return buildResult(form, turnCount, totalPatches, {
|
|
1747
2106
|
ok: false,
|
|
1748
2107
|
reason: "cancelled"
|
|
1749
2108
|
}, inputContextWarnings, stepResult.issues);
|
|
1750
|
-
|
|
2109
|
+
let llmStats;
|
|
2110
|
+
if (stats) llmStats = {
|
|
2111
|
+
inputTokens: stats.inputTokens,
|
|
2112
|
+
outputTokens: stats.outputTokens,
|
|
2113
|
+
toolCalls: stats.toolCalls.length > 0 ? stats.toolCalls : void 0
|
|
2114
|
+
};
|
|
2115
|
+
stepResult = harness.apply(patches, stepResult.issues, llmStats);
|
|
1751
2116
|
totalPatches += patches.length;
|
|
1752
2117
|
turnCount++;
|
|
1753
2118
|
if (options.onTurnComplete) try {
|
|
@@ -1757,10 +2122,11 @@ async function fillForm(options) {
|
|
|
1757
2122
|
issuesShown: stepResult.issues.length,
|
|
1758
2123
|
patchesApplied: patches.length,
|
|
1759
2124
|
requiredIssuesRemaining: requiredIssues.length,
|
|
1760
|
-
isComplete: stepResult.isComplete
|
|
2125
|
+
isComplete: stepResult.isComplete,
|
|
2126
|
+
stats
|
|
1761
2127
|
});
|
|
1762
2128
|
} catch {}
|
|
1763
|
-
if (!stepResult.isComplete) stepResult = harness.step();
|
|
2129
|
+
if (!stepResult.isComplete && !harness.hasReachedMaxTurns()) stepResult = harness.step();
|
|
1764
2130
|
}
|
|
1765
2131
|
if (stepResult.isComplete) return buildResult(form, turnCount, totalPatches, { ok: true }, inputContextWarnings);
|
|
1766
2132
|
return buildResult(form, turnCount, totalPatches, {
|
|
@@ -1782,5 +2148,4 @@ async function fillForm(options) {
|
|
|
1782
2148
|
const VERSION = "0.1.0";
|
|
1783
2149
|
|
|
1784
2150
|
//#endregion
|
|
1785
|
-
export { parseForm as _, resolveModel as a, createMockAgent as c, coerceInputContext as d, coerceToFieldPatch as f, ParseError as g, serializeSession as h, getProviderNames as i, FormHarness as l, parseSession as m, fillForm as n, createLiveAgent as o, findFieldById as p, getProviderInfo as r, MockAgent as s, VERSION as t, createHarness as u };
|
|
1786
|
-
//# sourceMappingURL=src-DBD3Dt4f.mjs.map
|
|
2151
|
+
export { parseForm as _, resolveModel as a, createMockAgent as c, coerceInputContext as d, coerceToFieldPatch as f, ParseError as g, serializeSession as h, getProviderNames as i, FormHarness as l, parseSession as m, fillForm as n, createLiveAgent as o, findFieldById as p, getProviderInfo as r, MockAgent as s, VERSION as t, createHarness as u };
|