Enable correction-aware semantic reconciliation

This commit is contained in:
2026-08-27 00:08:05 +00:00
parent a26d6ed042
commit 04ba87e174
14 changed files with 195 additions and 51 deletions

View File

@@ -49,6 +49,7 @@ type Request struct {
ProfileID string
StructuredOutputRepairAttempts *int
SessionID string
Correction *contracts.SemanticCorrection
}
// ResultDisposition classifies a provider-neutral reconciliation outcome.
@@ -69,6 +70,7 @@ type Result struct {
issues []Issue
discardedGroupCount int
candidateMappings []CandidateMapping
modelCandidate *contracts.ModelCandidate
}
// Disposition returns the classified outcome.
@@ -88,6 +90,16 @@ func (result Result) CandidateMappings() []CandidateMapping {
return append([]CandidateMapping(nil), result.candidateMappings...)
}
// ModelCandidate returns an owned copy of the proposal response when a model
// completion produced this result.
func (result Result) ModelCandidate() *contracts.ModelCandidate {
candidate, err := contracts.CloneModelCandidate(result.modelCandidate)
if err != nil {
return nil
}
return candidate
}
func (result Result) planCopy() Plan {
return Plan{groups: result.plan.Groups()}
}
@@ -162,8 +174,12 @@ func (engine *Engine) Reconcile(ctx context.Context, request Request) (Result, e
if err := ctx.Err(); err != nil {
return Result{}, fmt.Errorf("semantic reconciliation %q: context error before completion: %w", request.StageName, err)
}
correction, err := contracts.CloneSemanticCorrection(request.Correction)
if err != nil {
return Result{}, fmt.Errorf("semantic reconciliation %q: clone correction: %w", request.StageName, err)
}
var response ProposalResponse
_, err = engine.client.CompleteStructured(ctx, contracts.StructuredCompletionRequest{
completion, err := engine.client.CompleteStructured(ctx, contracts.StructuredCompletionRequest{
StageName: request.StageName,
PromptID: engine.prompt.ID,
PromptVersion: engine.prompt.Version,
@@ -171,6 +187,7 @@ func (engine *Engine) Reconcile(ctx context.Context, request Request) (Result, e
SessionID: request.SessionID,
StructuredOutputRepairAttempts: request.StructuredOutputRepairAttempts,
Inputs: preparation.Materials(),
Correction: correction,
}, &response)
if err != nil {
if errors.Is(err, contracts.ErrInvalidStructuredOutput) {
@@ -179,6 +196,11 @@ func (engine *Engine) Reconcile(ctx context.Context, request Request) (Result, e
}
return Result{}, fmt.Errorf("semantic reconciliation %q: complete structured output: %w", request.StageName, err)
}
candidate, err := contracts.NewModelCandidate(completion.Content, contracts.CorrectionProtocolSingleResponseV1)
if err != nil {
return Result{}, fmt.Errorf("semantic reconciliation %q: own model candidate: %w", request.StageName, err)
}
result.modelCandidate = candidate
assessment := preparation.Assess(response)
result.plan = assessment.Plan()