Repair rejected corrections in independent branches

This commit is contained in:
2026-11-11 04:29:18 +00:00
parent a5003a1e52
commit d927c61199
9 changed files with 451 additions and 22 deletions

View File

@@ -65,6 +65,7 @@ type WorkUnitOutcome struct {
Section contracts.SectionMetadata `json:"section"`
State outcomes.WorkState `json:"state"`
CorrectionsApplied int `json:"corrections_applied"`
Repairs []RepairOutcome `json:"-"`
Operations []outcomes.Operation `json:"operations,omitempty"`
}
@@ -186,6 +187,16 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (RunOutput, error) {
if input.CaptureCandidates {
candidates = append(candidates, pipelineResult.Candidates...)
}
if pipelineErr == nil && ctx.Err() != nil {
pipelineErr = ctx.Err()
for i := range pipelineResult.WorkUnits {
for j := range pipelineResult.WorkUnits[i].Repairs {
if pipelineResult.WorkUnits[i].Repairs[j].Outcome == "approved" {
pipelineResult.WorkUnits[i].Repairs[j].Outcome = "interrupted"
}
}
}
}
if pipelineErr != nil {
failed := ModuleResult{
StageIndex: spec.Index, StageID: spec.ID,
@@ -209,6 +220,18 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (RunOutput, error) {
updated, applied, skipped, appliedBySection, applyErr := applyWithinSections(sections, pipelineResult.Approved, policy, glossaryView.Protection, spec.ModuleKey == modulecatalog.KeySpokenWord)
if applyErr != nil {
for i := range pipelineResult.WorkUnits {
unit := &pipelineResult.WorkUnits[i]
unit.ModuleIndex = moduleIndex
unit.State = outcomes.WorkInterrupted
for j := range unit.Repairs {
if unit.Repairs[j].Outcome == "approved" {
unit.Repairs[j].Outcome = "interrupted"
}
}
}
copy(workUnits[moduleIndex*len(sections):(moduleIndex+1)*len(sections)], pipelineResult.WorkUnits)
results = append(results, ModuleResult{StageIndex: spec.Index, StageID: spec.ID, ModuleKey: spec.ModuleKey, ModuleInstance: spec.InstanceName, ReplacementPolicy: policy, Status: ModuleStatusFailed, ProposalCount: pipelineResult.ProposalCount, Operations: pipelineResult.Operations, ValidatorDecisions: pipelineResult.ValidatorDecisions, ValidatorRejected: pipelineResult.ValidatorRejected, ErrorMessage: applyErr.Error()})
return snapshot(), fmt.Errorf("module %q application failed: %w", spec.InstanceName, applyErr)
}
copy(workUnits[moduleIndex*len(sections):(moduleIndex+1)*len(sections)], pipelineResult.WorkUnits)
@@ -218,6 +241,22 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (RunOutput, error) {
unit.State = outcomes.WorkCompleted
unit.CorrectionsApplied = appliedBySection[sectionPos]
}
for i := range workUnits[moduleIndex*len(sections) : (moduleIndex+1)*len(sections)] {
unit := &workUnits[moduleIndex*len(sections)+i]
for j := range unit.Repairs {
branch := &unit.Repairs[j]
if branch.Outcome != "approved" {
continue
}
branch.Outcome = "approved_skipped"
for _, change := range applied {
if change.ProposalIndex == branch.ProposalIndex {
branch.Outcome = "applied"
break
}
}
}
}
attributeApplyFiltering(sections, pipelineResult.Approved, skipped, policy, workUnits[moduleIndex*len(sections):(moduleIndex+1)*len(sections)])
sections = updated
moduleOperations := make([]outcomes.Operation, 0)
@@ -310,6 +349,7 @@ type sectionProposalResult struct {
sectionPos int
section chunking.Section
corrected []proposals.CorrectionProposal
references []int
exchange *structuredoutput.Exchange
operations []outcomes.Operation
started bool
@@ -317,6 +357,7 @@ type sectionProposalResult struct {
}
type sectionValidationResult struct {
repairs []RepairOutcome
sectionPos int
enriched []proposals.EnrichedCorrectionProposal
approved []proposals.EnrichedCorrectionProposal
@@ -379,6 +420,7 @@ func collectSectionProposals(ctx context.Context, input collectSectionProposalsI
sectionPos: sectionPos,
section: section,
corrected: proposalResult.Proposals,
references: proposalResult.SegmentReferences,
exchange: proposalResult.Exchange,
operations: proposalResult.Operations,
started: true,
@@ -514,8 +556,18 @@ func runModulePipeline(ctx context.Context, input collectSectionProposalsInput)
GlossaryView: input.GlossaryView,
ReportDiagnosticError: input.ReportDiagnosticError,
})
var repairs []RepairOutcome
if err == nil && input.Spec.Settings.LLM.CorrectionRepairAttempts > 0 {
promptID := ""
if provider, ok := input.Module.(interface{ RepairPromptID() string }); ok {
promptID = provider.RepairPromptID()
}
repairInput := validateSectionCandidatesInput{Spec: input.Spec, Policy: input.Policy, WorkingTranscript: transcriptFromSection(sectionResult.section), SectionIndex: &sectionMetadata.Index, Validators: validatorsOrdered, SectionEnriched: enriched, Exchange: sectionResult.exchange, ValidationLLMClient: input.ValidationClient, DiagnosticsDir: input.ValidationDiagnosticsDir, GlossaryView: input.GlossaryView, ReportDiagnosticError: input.ReportDiagnosticError}
validated, repairs, err = repairCandidates(runCtx, repairInput, sectionResult.references, validated, promptID)
}
setErr(err)
validationResults <- sectionValidationResult{
repairs: repairs,
sectionPos: sectionPos,
enriched: enriched,
approved: validated.approved,
@@ -547,6 +599,7 @@ func runModulePipeline(ctx context.Context, input collectSectionProposalsInput)
}
unit := &out.WorkUnits[i]
unit.Operations = append(unit.Operations, res.operations...)
unit.Repairs = res.repairs
mergeFilteredProposals(unit, res.filtered)
if res.err == nil {
unit.State = outcomes.WorkCompleted
@@ -578,6 +631,13 @@ func runModulePipeline(ctx context.Context, input collectSectionProposalsInput)
}
if err := getErr(); err != nil {
for i := range out.WorkUnits {
for j := range out.WorkUnits[i].Repairs {
if out.WorkUnits[i].Repairs[j].Outcome == "approved" {
out.WorkUnits[i].Repairs[j].Outcome = "interrupted"
}
}
}
return out, err
}