diff --git a/packages/markform/src/engine/inspect.ts b/packages/markform/src/engine/inspect.ts index e777d7a2..f490616d 100644 --- a/packages/markform/src/engine/inspect.ts +++ b/packages/markform/src/engine/inspect.ts @@ -187,7 +187,7 @@ function mapValidationToInspectReason(vi: ValidationIssue): IssueReason { if ( vi.code === 'MULTI_SELECT_TOO_FEW' || vi.code === 'STRING_LIST_MIN_ITEMS' || - vi.message.includes('at least') + msg.includes('at least') ) { return 'min_items_not_met'; } @@ -419,7 +419,6 @@ export function isCheckboxComplete(form: ParsedForm, fieldId: Id): boolean { return true; // Non-checkbox fields are not blocking } - const checkboxField = field; const response = form.responsesByFieldId[fieldId]; // If no response or not answered, checkbox is not complete @@ -433,13 +432,13 @@ export function isCheckboxComplete(form: ParsedForm, fieldId: Id): boolean { } const values = value.values; - const optionIds = checkboxField.options.map((o) => o.id); - const mode = checkboxField.checkboxMode; + const optionIds = field.options.map((o) => o.id); + const mode = field.checkboxMode; if (mode === 'multi') { // Multi mode: all options must be done or na (not todo, incomplete, or active) // If minDone is set, at least that many must be done - const minDone = checkboxField.minDone; + const minDone = field.minDone; if (minDone !== undefined) { const doneCount = optionIds.filter((id) => values[id] === 'done').length; return doneCount >= minDone; @@ -488,8 +487,7 @@ export function findBlockingCheckpoint(form: ParsedForm): BlockingCheckpointResu continue; } - const checkboxField = field; - if (checkboxField.approvalMode === 'blocking' && !isCheckboxComplete(form, fieldId)) { + if (field.approvalMode === 'blocking' && !isCheckboxComplete(form, fieldId)) { return { index: i, fieldId }; } } diff --git a/packages/markform/src/engine/summaries.ts b/packages/markform/src/engine/summaries.ts index 760dbb8f..a86b57ae 100644 --- a/packages/markform/src/engine/summaries.ts +++ b/packages/markform/src/engine/summaries.ts @@ -157,11 +157,10 @@ function isFieldSubmitted(field: Field, value: FieldValue | undefined): boolean } case 'checkboxes': { const v = value as CheckboxesValue; - const checkboxField = field; // For checkboxes, check if any option has been changed from default - const mode = checkboxField.checkboxMode ?? 'multi'; + const mode = field.checkboxMode ?? 'multi'; - for (const opt of checkboxField.options) { + for (const opt of field.options) { const state = v.values[opt.id]; if (mode === 'explicit') { // In explicit mode, "unfilled" is default, anything else is submitted diff --git a/packages/markform/src/harness/fillRecordCollector.ts b/packages/markform/src/harness/fillRecordCollector.ts index 270b0f56..0b0420b8 100644 --- a/packages/markform/src/harness/fillRecordCollector.ts +++ b/packages/markform/src/harness/fillRecordCollector.ts @@ -571,22 +571,6 @@ export class FillRecordCollector implements FillCallbacks { ); } - private findTurnKeyForExecutionId( - executionId: string, - turnStartEvents: Map, - ): string | undefined { - // Find the most recent turn for this executionId - let latestKey: string | undefined; - let latestTime = ''; - for (const [key, event] of turnStartEvents) { - if (event.executionId === executionId && event.timestamp > latestTime) { - latestKey = key; - latestTime = event.timestamp; - } - } - return latestKey; - } - private normalizeInput(input: unknown): Record { if (input && typeof input === 'object' && !Array.isArray(input)) { return input as Record; diff --git a/packages/markform/src/harness/programmaticFill.ts b/packages/markform/src/harness/programmaticFill.ts index 36dc5fa1..1f440d72 100644 --- a/packages/markform/src/harness/programmaticFill.ts +++ b/packages/markform/src/harness/programmaticFill.ts @@ -581,6 +581,7 @@ export async function fillForm(options: FillOptions): Promise { additionalTools: options.additionalTools, callbacks: mergedCallbacks, maxStepsPerTurn: options.maxStepsPerTurn, + executionId: serialExecutionId(0), toolChoice: options.toolChoice, signal: options.signal, maxRetries: options.maxRetries, @@ -639,10 +640,8 @@ export async function fillForm(options: FillOptions): Promise { mergedCallbacks.onTurnStart({ turnNumber: turnCount + 1, issuesCount: stepResult.issues.length, - // Default to order 0, serial execution for non-parallel fills - // Parallel harness will override these values order: 0, - executionId: '0-serial', + executionId: serialExecutionId(0), }); } catch { // Ignore callback errors @@ -802,7 +801,7 @@ export async function fillForm(options: FillOptions): Promise { patches, rejectedPatches: stepResult.rejectedPatches ?? [], coercionWarnings: stepResult.coercionWarnings, - executionId: '0-serial', + executionId: serialExecutionId(0), }); } catch { // Ignore callback errors @@ -1166,7 +1165,7 @@ async function runMultiTurnForItems( items: ExecutionPlanItem[], targetRoles: string[], maxPatchesPerTurn: number, - _maxIssuesPerTurn: number, + maxIssuesPerTurn: number, maxTurnsTotal: number, startTurn: number, options: FillOptions, @@ -1212,6 +1211,9 @@ async function runMultiTurnForItems( return true; }); + // Cap issues shown to agent per turn (consistent with serial path) + scopedIssues = scopedIssues.slice(0, maxIssuesPerTurn); + if (scopedIssues.length === 0) break; // All items filled // Fire turn callback @@ -1291,9 +1293,11 @@ async function runMultiTurnForItems( // Apply patches let lastCoercionWarnings: PatchWarning[] | undefined; + let turnPatchesApplied = 0; if (response.patches.length > 0) { const applyResult = applyPatches(form, response.patches); - patchesApplied += applyResult.appliedPatches.length; + turnPatchesApplied = applyResult.appliedPatches.length; + patchesApplied += turnPatchesApplied; previousRejections = applyResult.rejectedPatches; lastCoercionWarnings = applyResult.warnings; } else { @@ -1309,7 +1313,7 @@ async function runMultiTurnForItems( mergedCallbacks?.onTurnComplete?.({ turnNumber: startTurn + turnsUsed, issuesShown: scopedIssues.length, - patchesApplied: response.patches.length, + patchesApplied: turnPatchesApplied, requiredIssuesRemaining: requiredIssues.length, isComplete: postInspect.isComplete, stats: response.stats,